面向对象—JS对象的讲解
一、Object.create方法
- Object.create是ES5新增的一个静态方法,用来定义一个实例对象。
- 该方法可以指定对象的原型和对象特征,使用现有的对象来提供新创建的对象的proto。具体用法如下
Object.create(prototype, descriptors)
- prototype:必须参数,指定原型对象,可以为null
- descriptors:可选参数,包含一个或多个属性描述符的 JS对象。属性描述符包括数据特性和访问器特性,其中数据特性说明如下
- value:指定属性值
- writable:默认为 false,设置属性值是否可写
- enumerable:默认为false,设置属性是否可枚举(for/in)
- configurable:默认为false,设置是否可修改属性特性和删除属性
var obj1 = {name: "对象obj1"} // 字面量创建的对象,其原型指向 object console.log(obj1); console.log("obj1的原型:",obj1.__proto__); var obj2 = Object.create(null, { // 创建一个没有原型对象的对象 name: { value: "对象obj2", writable: false } }) console.log(obj2); console.log("obj2的原型:",obj2.__proto__); //undefind var obj3 = Object.create(obj1) // 创建一个原型指向obj1的对象 console.log(obj3); console.log(obj3.name); // "对象obj1"。 obj3原型指向obj1,所以继承了obj1的属性。
二、对象的 constructor属性(即对象的构造函数)
function MyArry() { } // 创建一个数组构造函数 var arr1 = new MyArry() // 这里的 MyArry 肯定没有 数组相关的属性方法。如,push函数 // arr2.push(1,2,3) // 这里 MyArry的实例没有push方法 console.log(arr1); MyArry.prototype = Array.prototype; var arr2 = new MyArry() arr2.push(1,2,3) // 这里arr2对象,就拥有 Array实例的属性方法了.如,push console.log(arr2); // MyArry(3) [1,2,3] console.log(arr2.constructor); // Array() ,对象的构造函数引用出现问题,按理应该是指向MyArry。因为arr2是通过new MyArry创建的。 // 解决对象构造函数,引用问题 MyArry.prototype.constructor = MyArry console.log(arr2.constructor);
总结:
- 一旦我们修改构造函数的原型对象,为防止引用出现问题,同时也要修改原型对象的constructor属性
- constructor属性表示原型对象和构造函数之间的关联关系(实例对象和构造函数之间是存在指向关系的)。
这个属性只是表明 对象和构造函数之间的关联关系,本身并没用什么特别的用途。【至少目前没发现有什么用】
对constructor的使用:
对 constructor 的使用,只是因为修改构造函数的原型对象时,为防止出现引用问题。
function Star(uname, age){ this.uname = uname; this.age = age; } Star.prototype = { // 这里修改了 构造函数的原型对象,而不是给原型对象添加属性。下面必须重新将构造函数重新指向回去。 construtor: Star, // 使用 construtor 属性,重新设置 对象的 构造函数。 sing: function(){ console.log("我会唱歌"); }, movie: function(){ console.log("我会演电影"); } } var ldh = new Star("刘德华", 18) console.log(ldh);
总结:construtor属性只是表示 对象和构造函数之间的关系。没有设置construtor属性,从使用上来说,里面的方法还是可以正常调用的。
三、Object.fn和 obj.fn 的区别
JS的面向对象是基于原型实现的。默认创建的对象都是 Object 类型的实例,所以JS对象中都会有 Object.prototype 上的方法。如,obj.hasOwnProperty 方法。
但是使用继承的方法是有缺陷的,就是当一个对象的原型链不再指向 构造函数的原型对象时,这个对象就没有 Object.prototype上属性方法。所以JS把这些方法,在Object的静态属性上实现了下。
var obj = Object.create(null) // 创建一个 对象原型 为 null 的对象,即obj 对象的原型链不再有Object对象。所以obj不再有 Object.propoty上的属性方法 obj.hasOwnProperty('name') // 这里就会报错,因为 obj 自身和原型链上都 没有 hasOwnProperty方法 // 我们可以使用 Object上的静态方法,达到相同的功能。 Object.hasOwn(obj,'name') // 使用上肯定要传递一个操作对象进来的。
1、对象属性的可枚举性和所有权:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
a、属性的所有权是通过判断该属性是否直接属于某个对象决定的,而不是通过原型链继承的。
b、对象的属性不同于数组,属性是可以从原型上获取到的。所以遍历对象的属性,要分是不是自身的属性,是不是可枚举。
不然很多乱七八糟的属性都出来了,遍历就变得不可控了。(这里不讲人为去设置不可不枚举的功能,我们遍历对象,一般都是遍历自身的属性)
c、自定义的 普通object对象的属性都是可枚举属性。
d、有的操作会忽略enumerable为false的属性。https://www.cnblogs.com/JiAyInNnNn/p/11457323.html
目前,有四个操作会忽略enumerable为false的属性。
for…in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
2、对象属性的遍历:https://www.cnblogs.com/chenyablog/p/6477866.html
a、Object.keys():返回一个数组,包括对象 自身的 (不含继承的)所有可枚举属性(不含Symbol属性)。然后使用数组的方法去遍历。【个人喜欢用这种】
b、使用 for..in..遍历:循环遍历对象 自身的 和 继承的 可枚举属性(不含Symbol属性)。
c、使用Object.getOwnPropertyNames(obj)遍历: 返回一个数组,包含对象 自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
d、使用Reflect.ownKeys(obj)遍历:返回一个数组,包含对象 自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举。
总结:普通的object对象属性的遍历,4种方法都可以。因为普通对象的属性都是可枚举的,也不会使用Symbol属性名,且没有继承的属性。如下创建的对象,
var obj = {'0':'a','1':'b','2':'c'};
3、js对象 属性的分类:https://juejin.cn/post/7033922034555944973
js对象属性分两种,数据属性(也是我们常用的)和 访问器属性。