【问题标题】:Traversing prototype chain using constructor.prototype使用 constructor.prototype 遍历原型链
【发布时间】:2013-06-30 20:59:25
【问题描述】:

如果我可以使用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?

不应该返回 MyConstructor 的原型 function() { [native code] }(在 Chrome 控制台中)吗?

【问题讨论】:

    标签: javascript constructor prototype


    【解决方案1】:

    所有构造函数都是全局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

    【讨论】:

      【解决方案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 执行后者……

      【讨论】:

        猜你喜欢
        • 2019-09-30
        • 2012-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-23
        • 2020-08-06
        • 2023-03-25
        • 2017-09-03
        相关资源
        最近更新 更多