如果我可以使用obj.constructor.prototype
来访问对象的原型,那么为什么我不能使用obj.constructor.prototype.constructor.prototype
来遍历原型链并且必须使用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?
不应该返回function() { [native code] }
的MyConstructor原型(在Chrome控制台中)吗?
答案 0 :(得分: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.prototype
的原型是Object.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()
方法。
这是一个很棒的visual reference。
答案 1 :(得分: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控制台有时会对显示未命名对象的有用标题感到困惑,但并不总是正确的。
如果你得到它的原型,它应该产生Object.prototype
,当你得到MyConstructor
函数本身的原型时它应该是Function.prototype
。请注意,您可以再次MyConstructor.constructor.prototype
执行后者...