这是我参与8月更文挑战的第三十一天,活动详情查看:8月更文挑战
__proto__
绝大多数(并非所有)浏览器支持一种非标准的方法来访问内部的[Prototype]属性:
a.__proto__ === Foo.prototype
这个奇怪的.__proto__(在ES6之前并非标准)属性神奇的引用了内部的[Prototype]对象,如果需要查找原型链的话,这个方法非常有用.甚至可以直接通过.__proto__....__proto__来遍历。
和.constructor一样,.__proto__实际上并不存在于正在使用的对象中。实际上,它和其他的常用函数(.toString()、.isPrototypeOf()等)一样,存在于内置的Object.prototype中。这些都是不可枚举的。
此外,.__proto__看起来很像一个属性,但是实际上它更像一个getter/setter。
.__proto__的实现大致上是这样的:
Object.defineProperty(Object.prototype,"__proto__",{
get:function(){
return Object.getPrototypeOf(this);
},
set:function(o){
Object.setPrototypeOf(this,o);
return o;
}
});
因此,获取值a.__proto__时,实际上是调用了a.__proto__()(调用getter函数)。虽然getter函数存在于Object.prototype对象中,但是它的this指向对象a,所以和Object.getPrototypeOf(a)结果相同。
a.__proto__是可设置属性,之前的代码中使用ES6的Object.setPrototypeOf(..)进行设置。然而,一般来说并不需要修改已有对象的[Prototype].一些框架会使用非常复杂和高端的技术来实现“子类”机制,但是通常来说,不推荐这种用法,因为这会极大的增加代码的阅读难度和维护难度。
ES6的class关键字可以在内置的类型(如Array)上实现类似“子类”的功能。
我们只有在一些特殊的情况下需要设置函数默认的.prototype对象的[Prototype],让它引用其他对象(除了Object.prototype)。这样可以避免使用全新的对象替换默认对象。此外,最好把[Prototype]对象关联看成是只读特性,从而增加代码的可读性。
JavaScript社区中对于双下划线有个非官方的称呼,他们会把类似__proto__的属性成为“dunder”,所以__proto__又被成为dunder proto。