你不知道的 JavaScript 系列上( 54) - 检查 [[Prototype]]
instanceof
function Foo() { // ... } Foo.prototype.blah = ...; var a = new Foo();
我们如何找到 a 的 “祖先” (委托关联)呢?第一种方法:
a instanceof Foo; // true
instanceof 操作符的左操作符是一个普通的对象,右操作数是一个函数。 instanceof 回答的问题是:在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象?可惜,这个方法只能处理对象和函数之间的关系。如果想判断两个对象之间是否通过 [[Prototype]] 链关联,只用 instanceof 无法实现。
isPrototypeOf
Foo.prototype.isPrototypeOf(a); // true
isPrototypeOf 回答的问题是:在 a 的整条 [[Prototype]] 链中是否出现过 Foo.prototype
这里我们只需要两个对象就可以判断它们之间的关系。举例来说:
// 非常简单: b 是否出现在 c 的 [[Prototype]]链中?
b.isPrototypeOf(c)
这个方法并不需要使用函数,它直接使用 b 和 c 之间的对象引用来判断它们的关系。
getPrototypeOf
我们也可以直接获取一个对象的 [[Prototype]] 链。在 ES5 中,标准的方法是:
Object.getPrototypeOf(a);
Object.getPrototypeOf(a) === Foo.prototype; // true
__proto__
绝大多数浏览器也支持一种非标准的方法来访问内部 [[Prototype]] 属性:
a.__proto__ === Foo.prototype; // true
这个奇怪的 __proto__ 属性 “神奇地” 引用了内部的 [[Prototype]] 对象。这个和 .constructor 一样,实际上并不存在于正在使用的对象中,它和其他的常用函数(.toString(), .isPrototypeof(...)等等)一样,存在于内置的 Object.prototype中。它们是不可枚举的
__proto__ 看起来很像一个属性,但是实际上它更像一个 getter/setter。实际上大致是这样的
Object.definePrototype(Object.prototype, "__proto__", { get: function() { return Object.getPrototypeOf(this); }, set: function() { // ES6中的 setPrototypeOf(...) Object.setPrototypeOf(this, o); return o; } })
因此,访问 a.__proto__ 实际上是调用了 getter 函数,虽然 getter 函数存在于 Object.prototype 对象中,但是它的 this 指向对象 a,所以和 Object.getPrototypeOf(a) 结果相同。