7

If I can use obj.constructor.prototype to access the prototype of an object, then why can't I use obj.constructor.prototype.constructor.prototype to traverse the prototype chain and have to use Object.getPrototypeOf?

function MyConstructor()
{
    this.prop = 1;
}

var o = new MyConstructor();

console.log(o.constructor.prototype) // MyConstructor

console.log(o.constructor.prototype.constructor.prototype) // MyConstructor?

Shouldn't it return the prototype of MyConstructor which is function() { [native code] } (in Chrome console)?

4

2 回答 2

8

所有构造函数都是全局Function对象的实例:

function Foo(){ this.x = 1 }; // Dummy constructor function

console.log(Foo instanceof Function) // => true; Foo is an instance of global Function constructor

所有原型都是全局Object对象的实例:

console.log(Foo.prototype instanceof Object); // => true

定义构造函数时Foo,它会自动Foo.prototype附加一个对象,您可以将其视为“空白”对象,根据上述,它本身继承自全局Object对象。换句话说,的原型Foo.prototypeObject.prototype

function Foo(){ this.x = 1 }; // Dummy constructor function

console.log(Foo.prototype); // Foo (object); already exists

console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // => true

由于Foo.prototype是一个空白对象,人们会期望它的构造函数是全局Object构造函数:

function Foo(){ this.x = 1 }; // Dummy constructor function

console.log(Foo.prototype.constructor) // => function Foo() { this.x = 1; } ??

console.log(Foo.prototype.constructor === Object.prototype.constructor); // => false

但是,此“空白”对象具有显式自引用constructor属性,该属性指向function Foo(){ this.x = 1 }并覆盖或“屏蔽”您期望的默认构造函数属性:

function Foo(){ this.x = 1 }; // Dummy constructor function

delete Foo.prototype.constructor; // Delete explicit constructor property

console.log(Foo.prototype.constructor) // => function Object() { [native code] }

console.log(Foo.prototype.constructor === Object.prototype.constructor); // => true

因此不能使用obj.constructor.prototype递归遍历原型链,必须依赖Object.getPrototypeOf()方法。

这是一个很好的视觉参考

于 2013-06-30T21:10:25.013 回答
2

如果我可以使用 obj.constructor.prototype 来访问对象的原型

你一般不能。考虑这种方法的工作原理:

var proto = MyConstructor.prototype;
// has an (nonenumberable) property "constructor"
proto.hasOwnProperty("constructor"); // `true`
// that points [back] to
proto.constructor; // `function MyConstructor() {…}`

如您所见,这是一个循环的属性结构。当你这样做

var o = new MyConstructor();
// and access
o.constructor; // `function MyConstructor() {…}`
// then it yields the value that is inherited from `proto`
// as `o` doesn't have that property itself:
o.hasOwnProperty("constructor"); // `false`

但这仅适用于从原型对象o继承constructor属性的对象,并且该对象具有指向原型对象的有用值。考虑到

var o = {};
o.constructor = {prototype: o};

哎呀。在这里访问会o.constructor.prototype产生o本身,它可能是任何其他无意义的值。结构实际上与上面的相同MyConstructor.prototype- 如果您访问proto.constructor.prototype.constructor.prototype[.constructor.prototype…],您将不会得到任何其他东西,而只是proto.

那为什么我不能obj.constructor.prototype.constructor.prototype用来遍历原型链而不得不使用Object.getPrototypeOf呢?

因为您被困在循环结构中,因为MyConstructor.prototype) 本身具有该constructor属性,而不是继承自Object.prototype. 为了真正获得下一个对象真正的原型链,您必须使用Object.getPrototypeOf.

var o = new MyConstructor();
console.log(o.constructor.prototype) // MyConstructor

其实应该是的MyConstructor.prototype。Chrome 控制台有时会在显示未命名对象的有用标题时感到困惑,而且并不总是正确的。

如果你得到它的原型,它应该是 yield Object.prototype,当你得到MyConstructor函数本身的原型时,它应该是Function.prototype。请注意,您可以MyConstructor.constructor.prototype再次执行后者……</p>

于 2013-06-30T22:44:43.220 回答