Javascript __proto__输出

时间:2014-06-02 23:05:46

标签: javascript inheritance prototype

下面是一些示例,展示了基于如何定义和创建对象的原型继承的不同行为。我区分"原型属性"一个物体,例如someObject.prototype和"原型参考" (我认为应该引用someObject继承的对象?)。

示例1

这似乎是保留父对象原型属性的方法。这不是推荐的继承方式吗?

// create object whose prototype reference is Object; add stuff.
var Parent = Object.create(Object);
Parent.a = "1";
Parent.f = function() { return true; };

// add stuff to prototype property
Parent.prototype.b = 1;
Parent.prototype.g = function() { return false; };

// create an object whose prototype reference is Parent (??)
var Child = Object.create(Parent);

console.log(Parent.__proto__)  // [Function: Object]
console.log(Parent.prototype)  // { b: 1, g: [Function] }
console.log(Child.__proto__)   // { a: '1', f: [Function] }
console.log(Child.prototype)   // { b: 1, g: [Function] }
  1. 我希望Child.__proto__Parent名称Parent.__proto__的方式命名Object

  2. 我们看到Child的原型引用指向Parent的属性,而不是Parent.prototype的属性。至少对我来说,这是违反直觉的,正如我原本预期的那样,我会看到Parent.prototype的属性bg

  3. 示例2

    混合结果。

    // use a constructor instead.
    var Parent = function () {
        this.a = "1";
        this.f = function() { return true; };
    }
    
    // again, add stuff to prototype property.
    Parent.prototype.b = 1;
    Parent.prototype.g = function() { return false; };
    
    // create an object whose prototype reference is Parent (??)
    var Child = new Parent();
    
    // create differently
    var Sibling = Object.create(Parent);
    
    console.log(Parent.__proto__)   // [Function: Empty]
    console.log(Parent.prototype)   // { b: 1, g: [Function] }
    
    console.log(Child.__proto__)    // { b: 1, g: [Function] }
    console.log(Child.prototype)    // undefined
    
    console.log(Sibling.__proto__)  // [Function]
    console.log(Sibling.prototype)  // { b: 1, g: [Function] }
    
    1. 此处,Child的原型参考Parents.prototype的属性。这是我上面的预期?

    2. 另一方面,Sibling的原型参考现在是一个函数,它是Parent的原型参考。

    3. 示例3

      这似乎是保留父对象原型引用的方法,但是你丢失了它的原型属性。

      // create object constructor; add stuff.
      var Parent = function () {
          this.a = "1";
          this.f = function() { return true; };
      }
      
      // add stuff to prototype property.
      Parent.prototype.b = 1;
      Parent.prototype.g = function() { return false; };
      
      // create an object whose prototype reference is Parent (??)
      var Child = function() {
          this.c = "2";
      };
      
      // supposed Ad-hoc prototype inheritance
      Child.prototype = Object.create(Parent.prototype)
      
      console.log(Parent.__proto__)  // [Function: Empty]
      console.log(Parent.prototype)  // { b: 1, g: [Function] }
      console.log(Child.__proto__)   // [Function: Empty]
      console.log(Child.prototype)   // {}
      

      示例1 中显示的方法是否首选,因为您可以访问父级的原型属性,自己的属性以及Object的属性/方法?我在其他帖子中读过,其中一些继承方式应该是平等的......这是不正确的。此外,我还阅读了其他帖子,例如here示例3 是要走的路。或许我只是不确定__proto__代表什么......

      感谢您对这些混合和匹配情况之间的差异所做的任何澄清!

2 个答案:

答案 0 :(得分:2)

  

我区分"原型成员"一个物体,例如someObject.prototype和"原型参考"

良好的术语,区分它们是理解它们的第一步and the difference between them

  

(我认为应该引用someObject继承的对象?)。

完全。与.prototype成员相比,您可以通过Object.getPrototypeOf(obj)或非标准.__proto__属性访问protypte引用。

  

示例1

     

这不是推荐的继承方式吗?

它是一种方式进行继承,以及最纯粹的原型继承形式。请注意,ParentChild是普通对象,不涉及构造函数。

// create object whose prototype reference is Object; add stuff.
var Parent = Object.create(Object);

这是第一个错误:您继承了Object 函数(基于构造函数模式,见下文)。你应该做的

var Parent = {};
// or
var Parent = Object.create(Object.prototype);
// add stuff to prototype member
Parent.prototype.b = 1;
Parent.prototype.g = function() { return false; };

然而,.prototype成员在这种继承模式中没有任何意义。它只是一个普通的属性,在这种情况下,它继承自Object。你实际上在这里修改Object.prototype对象(大禁忌)!

// create an object whose prototype reference is Parent (??)
var Child = Object.create(Parent);

是的,那是Object.create所做的。

  

[例1/1]我原本期望Child。 proto 以同样的方式命名Parent. proto 命名Object。

它仅命名Object,因为它是一个命名函数。在运行时,无法从对象引用中知道变量名Parent

  

[例1/2]我们看到Child的原型引用指向Parent的成员而不是Parent.prototype的成员。至少对我来说这是违反直觉的,因为我原本希望看到Parent.prototype的成员b和g。

是的,您直接从Parent对象继承。 .prototype如上所述是微不足道的。 Child.prototype === Object.prototype(它继承了两次)。

  

示例2 - 改为使用构造函数。将东西添加到其原型成员。

// create an object whose prototype reference is Parent (??)
var Child = new Parent();
     

[例2/1]这里,Child的原型引用了Parents.prototype的成员。这是我上面所期待的?

没有。在这种情况下,new operator创建了对所提供的构造函数的.prototype成员的值的原型引用 - Parent.prototype

// create differently
var Sibling = Object.create(Parent);

同样,在这里,您要创建一个具有函数原型引用的对象。不是你想要的 - 而是使用

var sibling = Object.create(Parent.prototype);
Parent.call(sibling); // optionall apply the constructor on it, like `new` does
  

[例2/2]另一方面,兄弟姐妹的原型参考现在是一个功能,   这是Parent的原型参考。

更确切地说,它是Parent函数本身。这就是您Sibling继承.prototype财产的原因。

  

示例3 - 这似乎是保留父对象原型引用的方法,但是您丢失了原型成员:

// supposed Ad-hoc prototype inheritance
Child.prototype = Object.create(Parent.prototype)

这是为构造函数方式设置继承(原型引用)链所必需的。它是实施"类"的标准方法。 JavaScript中的模式。

console.log(Parent.__proto__)  // [Function: Empty]
console.log(Parent.prototype)  // { b: 1, g: [Function] }
console.log(Child.__proto__)   // [Function: Empty]
console.log(Child.prototype)   // {}

如您所见,ParentChild都是函数 - 构造函数是准确的。你需要调用它们:

var childInstance = new Child();
console.log(childInstance) // {c: "2"}
console.log(childInstance.prototype) // undefined - it's not a constructor
console.log(childInstance.__proto__) // {} - the Child.prototype object
console.log(childInstance.__proto__.__proto__) // the Parent.prototype object
console.log(childInstance.__proto__.__proto__.__proto__) // the Object.prototype object

然而,你忘记了一步。 childInstance确实从b继承了gParent.prototype,但没有在a中创建fParent个附加条件构造函数。对于correct inheritance in the constructor model,您还必须在每个实例上应用Parent构造函数,最好是在Child构造函数中:

function Child() {
    Parent.call(this);
    this.c = "2";
}
var childInstance = new Child();
console.log(childInstance) // {a: 1, f: [Function …], c: "2"}

答案 1 :(得分:0)

要了解Object.create的作用,首先需要了解为什么需要这样做。

JavaScript中原型设计的经典示例使原型成为继承对象的实例:

function Parent(field) {
    this.field = field;
}

Parent.prototype.getField = function () { return this.field; }

function Child(field, field2) {
    Parent.call(this, field);
    this.field2 = field2;
}

Child.prototype = new Parent(null); // oops

Child.prototype.getField2 = function () { return this.field2; }

那" oops"当我们希望它只继承方法Child.prototype时,field行会getField。你可以猜测这不是卫生的(语言方面的),并且可能会因为不那么重要的例子而变得混乱。

更简洁的方法是实例化未初始化的Parent

function inherit(parent) {
    function temp() {
    }
    temp.prototype = parent.prototype;
    return new temp();
}

Child.prototype = inherit(Parent);

该技术是使用相同的原型制作临时构造函数,这样在创建对象时,不会进行构造函数初始化。实际上,只建立了原型链。