原型和__proto__,哪种说法正确?

时间:2018-07-25 15:15:38

标签: javascript prototype

我试图理解JavaScript中基于原型的继承。我读了很多书,然后用谷歌搜索了几个小时。现在,我需要连接所有这些信息,并希望您能为我提供帮助。

如果以下3条正确的话:

  • JavaScript中的每个对象具有一个特殊的内部属性,我们可以通过.__proto__对其进行访问。
  • 所有构造函数都有一个匿名对象属性,我们可以通过.protootype访问该属性。
  • 实例对象__proto__属性指向其构造函数prototype对象属性。

让我们创建以下构造函数,该函数创建一个 Dog 对象:

function Dog(name, color) {
  this.name = name;
  this.color = color;

  this.bark = function() {
    return `Bark, bark! My name is ${this.name}`;
  }
}

现在让我们为我们的 Dog 对象创建一个实例:

let mini = new Dog('mini', 'black');

如果我们现在打开控制台并返回 mini ,则结果为:

enter image description here

按预期,实例对象 mini 继承了其构造函数的所有属性和方法。

但是这些继承的属性和方法都没有在其__proto__属性内。似乎它们都是直接继承给对象 mini 本身。

现在让我们向构造函数的原型对象添加一个新方法:

Dog.prototype.myBread = function() {
  return `My bread is ${this.bread}`;
}

如果我们现在在控制台中返回 mini ,则会得到以下结果:

enter image description here

再次,如预期的那样,将新方法 myBread 传递给我们的对象。但是这一次它显示在对象 mini __proto__内部,该对象引用(指向)构造函数中的 prototype对象属性。

现在从上面的简单实验中,我假设以下内容:

  1. 如果构造函数具有自己的属性和方法,则它们不属于其原型对象。这些属性和方法直接位于构造函数对象上。

  2. 但是,如果我们向构造函数的.protoype添加属性或方法,它们就会被添加到其原型对象中。为了证明这一点,我们无法访问Dog.myBread();,但是我们可以访问Dog.prototype.myBread();

  3. 添加到构造函数的.prototype中的
  4. 属性和方法落入构造函数的 prototype对象中,并且因为我们实例的__proto__对象引用该原型对象,我们可以在实例对象中访问它们。

  5. 如果构造函数具有自己的属性和方法,则它们不在其原型对象之内。这些属性和方法直接位于对象上,并自动传递给其所有实例。在这种情况下,__proto__ prototype属性不起作用,并且与继承过程无关!

现在,您能帮我看看我的假设是否正确? 我对最后一个假设特别好奇。

2 个答案:

答案 0 :(得分:2)

  

JavaScript中的每个对象都有一个特殊的内部属性,我们可以通过.__proto__

访问

不。每个JS对象都有一个内部[[prototype]]链接,我们可以通过Object.getPrototypeOf()访问该链接。 __proto__已过时,在所有对象上不可用。

  

所有构造函数均具有匿名对象属性,我们可以通过.protootype访问该属性。

是的,所有构造函数都具有带有对象的.prototype属性,但是我不确定为什么将其称为“匿名”。

  

实例对象的[[prototype]]链接指向其构造函数的prototype对象属性。

不是属性,而是对象本身。如果您要重新分配Constructor.prototype = …,则实例的[[prototype]]链接不会更改。调用Constructor.prototype时,链接是使用new的当前值设置的。是的。


  

按预期,实例对象mini继承了其构造函数的所有属性和方法。

不,您的第一个示例中没有继承。 barkcolorname属性由实例拥有。它们不属于构造函数,它们只是由实例上的构造函数代码创建的。

  
      
  1. 如果构造函数具有自己的属性和方法,则它们不属于其原型对象。这些属性和方法直接位于构造函数对象上。
  2.   

是的,.prototype.name是位于构造函数对象本身的属性。

(请注意,每个构造函数都是函数对象,也具有指向Function.prototype的[[prototype]]链接,但这在这里并不是特别有趣)

  
      
  1. 但是,如果我们将属性或方法添加到构造函数的.protoype中,则会将它们添加到其原型对象中。为了证明这一点,我们无法访问Dog.myBread();,但可以访问Dog.prototype.myBread();
  2.   

这听起来像是在说实话,是的。

  
      添加到构造函数的.prototype中的
  1. 属性和方法落入构造函数的 prototype对象中,因为实例对象的[[prototype]]引用了原型对象,我们可以在我们的实例对象中访问它们。
  2.   

是的,这是继承。

  
      
  1. 如果构造函数具有自己的属性和方法,则它们不在其原型对象之内。这些属性和方法直接位于对象上,并自动传递给其所有实例。在这种情况下,__proto__ prototype属性不起作用,并且与继承过程无关!
  2.   

是的,自己的属性与继承无关。

答案 1 :(得分:1)

编写Dog.myBread();时,您尝试调用的不是对象instanceOf Dog,而是仅调用Object(function)Dog,就像另一种语言的static字段一样