(09)Object.setPrototypeOf() & Object.getPrototypeOf() & __proto__
JS的对象继承是通过原型链实现的。ES6提供了更多原型对象的操作方法
①__proto__属性
这个属性用来读取或者设置当前对象的原型对象(prototype)
1 // ES5的写法 2 const fatherObj = {} 3 const sonObj = { 4 method:function(){} 5 } 6 obj.__proto__ = fatherObj 7 8 // ES6的写法 9 var sonObj01 = Object.create(fatherObj) 10 sonObj01.method = function(){}
- __proto__属性没有写入ES6的正文,而是写入了附录,原因是这个属性前后带有下划线,说明它本质上是一个内部属性,而不是一个正式的对外的API,只是由于浏览器的广泛支持,才被加入了ES6。
- 标准明确规定,只有浏览器必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在的。因此,无论从语义的角度,还是从兼容性的角度,都不要使用这个属性。而是使用下面的
Object.setPrototypeOf()
(写操作)、Object.getPrototypeOf()
(读操作)、Object.create()
(生成操作)代替。 - 如果一个对象本身部署了
__proto__
属性,该属性的值就是对象的原型
② Object.setPrototypeOf()
这个方法的作用与__proto__的作用相同,用来设置一个对象的原型对象(prototype),返回参数对象本身。它是ES6正式推荐的设置原型对象的方法。
1 // 格式 2 Object.setPrototypeOf(object,prototype) 3 4 // 用法 5 const o = Ojbect.setPrototypeOf({},null)
这个方法等同于下面的函数:
1 function setPrototypeOf(obj,proto){ 2 obj.__proto__ = proto; 3 return obj 4 }
示例:
1 let proto = {} 2 let obj = { a:1 } 3 Object.setPrototypeOf(obj,proto) 4 5 proto.b = 2 6 proto.c = 3 7 8 obj.a // 1 9 obj.b // 2 10 obj.c // 3
上面代码将proto
对象设为obj
对象的原型,所以从obj
对象可以读取proto
对象的属性
注意:
- 如果第一个参数不是对象,会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果
- 由于
undefined
和null
无法转为对象,所以如果第一个参数是undefined
或null
,就会报错(null和undefined的区别可见阮一峰博客)
③Object.getPrototypeOf()
这个方法与Object.setPrototypeOf()方法配套,用于读取一个对象的原型对象
Object.getPrototypeOf(obj)
注意:
- 如果参数不是对象,会被自动转为对象
- 如果参数是
undefined
或null
,它们无法转为对象,所以会报错
(10)Object.is()
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身,以及+0
等于-0
。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6提出了"Same-Value equuality"(同值相等)算法,用来解决这个问题。Object.is()就是部署这个算法的新方法。它用来比较两个值是否严格相等,与(===)的行为基本一致
1 Object.is('foo', 'foo') 2 // true 3 Object.is({}, {}) 4 // false
ES5可以通过以下代码,部署Object.is
1 Object.defineProperty(Object, 'is', { 2 value: function(x, y) { 3 if (x === y) { 4 // 针对+0 不等于 -0的情况 5 return x !== 0 || 1 / x === 1 / y; 6 } 7 // 针对NaN的情况 8 return x !== x && y !== y; 9 }, 10 configurable: true, 11 enumerable: false, 12 writable: true 13 });
(11)Object.isExtensible() & Object.isFrozen() & Object.isSealed()
①Object.isExtensible()
方法判断一个对象是否是可扩展的.
默认情况下,对象是可扩展的:即可以为他们添加新的属性。以及它们的 __proto__
属性可以被更改。Object.preventExtensions
,Object.seal
或 Object.freeze
方法都可以标记一个对象为不可扩展(non-extensible)
1 // 新对象默认是可扩展的. 2 var empty = {}; 3 Object.isExtensible(empty); // === true 4 5 // ...可以变的不可扩展. 6 Object.preventExtensions(empty); 7 Object.isExtensible(empty); // === false 8 9 // 密封对象是不可扩展的. 10 var sealed = Object.seal({}); 11 Object.isExtensible(sealed); // === false 12 13 // 冻结对象也是不可扩展. 14 var frozen = Object.freeze({}); 15 Object.isExtensible(frozen); // === false
注意:
- 在 ES5 中,如果参数不是一个对象类型,将抛出一个
TypeError
异常。在 ES6 中, non-object 参数将被视为一个不可扩展的普通对象,因此会返回 false 。
Object.isFrozen() 与 Object.isSealed() 分别用来对应Object.freeze()和Object.seal()
(12)Object.hasOwnProperty()
hasOwnProperty()
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
1 let obj = { 2 name: "张三", 3 age: 26 4 } 5 console.log(obj.hasOwnProperty('name')); // true 6 console.log(obj.hasOwnProperty('gender')); // false
(13)Object.isPrototypeOf()
isPrototypeOf()
方法用于测试一个对象是否存在于另一个对象的原型链上
注意:isPrototypeOf()
与 instanceof
运算符不同。在表达式 "object instanceof AFunction
"中,object
的原型链是针对 AFunction.prototype
进行检查的,而不是针对 AFunction
本身。
1 function Foo() { } 2 function Bar() { } 3 function Baz() { } 4 5 Bar.prototype = Object.create(Foo.prototype) // 让Bar继承自Foo 6 Baz.prototype = Object.create(Bar.prototype) // 让Baz继承自Bzr 7 // 继承关系:Foo->Bar->Baz 8 // 父--------->子 9 10 var baz = new Baz() 11 console.log(Baz.prototype.isPrototypeOf(Baz)); 12 console.log(Bar.prototype.isPrototypeOf(baz)); // true 13 console.log(Foo.prototype.isPrototypeOf(baz)); // true 14 console.log(Object.prototype.isPrototypeOf(baz)); // true
注意与instanceof操作符的不同:
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。- isPrototypeOf() 作用在两个对象的比较
(14)Object.propertyIsEnumerable()
propertyIsEnumerable()
方法返回一个布尔值,表示指定的属性是否可枚举
1 const object1 = {}; 2 const array1 = []; 3 object1.property1 = 42; 4 array1[0] = 42; 5 6 console.log(object1.propertyIsEnumerable('property1')); 7 // expected output: true 8 9 console.log(array1.propertyIsEnumerable(0)); 10 // expected output: true 11 12 console.log(array1.propertyIsEnumerable('length')); 13 // expected output: false
(15)Object.toLocaleString() & Object.toString()
①toLocaleString()
方法返回一个该对象的字符串表示。此方法被用于派生对象为了特定语言环境的目的(locale-specific purposes)而重载使用
用于覆盖toLocaleString的对象。在Object下的对象被改写了:
②toString()
方法返回一个表示该对象的字符串
每个对象都有一个toString()方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString()返回“[object type]”,其中type是对象的类型。以下代码说明了:
var o = new Object(); o.toString(); // returns [object Object]
可以使用toString()检测对象类型
可以通过toString(),来获取每个对象的类型。为了每个对象都能铜鼓Object.prototype.toString()来检测,所以需要使用call()或者apply的形式来调用。
1 var toString = Object.prototype.toString; 2 3 toString.call(new Date); // [object Date] 4 toString.call(new String); // [object String] 5 toString.call(Math); // [object Math] 6 7 //Since JavaScript 1.8.5 8 toString.call(undefined); // [object Undefined] 9 toString.call(null); // [object Null]
(16)Object.valueOf()
valueOf()
方法返回指定对象的原始值。
JavaScript调用valueOf
方法将对象转换为原始值。你很少需要自己调用valueOf
方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。
确实么用过,想了解可以查看MDN