为什么原型的构造函数会引用自己?

时间:2019-07-12 23:26:51

标签: javascript

来自Mozilla-javascript-docs

每个对象都有一个私有属性,该属性持有指向另一个称为其原型的对象的链接。该原型对象具有其自己的原型,依此类推,直到到达以null为原型的对象为止。 ,null没有原型,并充当该原型链中的最终链接。

第一个问题-我希望通过“每个对象都包含原型”,作者的意思是“每个功能对象”都包含 public < strong> prototype 属性,因为像这样的var myObj = {}对象没有任何 public 原型。

请参见下面的conole屏幕截图-注意使用{}创建的对象的公共原型属性(而不是私有__proto__)不存在- enter image description here

第二个问题-在阅读了上述文献后,当我检查了一个简单函数的原型链时,一开始它似乎无穷无尽-但是后来我意识到,原型实际上是指自身。与Mozilla's documentation中提到的方式不同,此处的原型链似乎并没有以null作为根。

我想这是为了支持基于原型的继承而设计的。但是,如果可以解释,我将不胜感激, 确切地说,原型构造函数中的这种自引用如何帮助实现这一目标

enter image description here

2 个答案:

答案 0 :(得分:3)

如果要查找此处描述的原型链:

  

每个对象都有一个私有属性,该属性持有指向另一个称为其原型的对象的链接。该原型对象具有自己的原型,依此类推,直到到达以null为原型的对象。根据定义,null没有原型,并充当该原型链中的最终链接。

您应该查看__proto__属性(它将指向被检查对象的内部原型)。

enter image description here

在这里,您看到myFunctionObj的内部原型为Function.prototype,而上一个__proto__的下一级将带您到Object.prototype,后者没有{{ 1}}(原型链的末尾)。

__proto__的{​​{1}}属性是指实例化对象的内部原型(例如prototype,然后是myFunctionObj),而不是const obj = new myFunctionObj();本身的内部原型。

通常,只有obj.__proto__ === myFunctionObj.prototype个具有myFunctionObj属性,并且它们的function将引用由.prototype创建的实例的内部原型 。普通对象没有.prototype属性(因为不能调用普通对象来实例化某些东西),但是您仍然可以使用new访问普通对象(或任何对象)的内部原型。 (或.prototype):

Object.getPrototypeOf

函数的.__proto__实际上只是对函数的自引用。

const obj = {};
console.log(
  obj.__proto__ === Object.prototype,
  Object.getPrototypeOf(obj) === Object.prototype,
);

当您已经引用了构造函数时,它不是很有用,但是当您引用一个实例但不知道其构造器时,它 很有用-具有原型继承性,可以访问实例的.prototype.constructor属性将为您提供用于构造它的函数:

function foo(){};
console.log(
  foo.prototype.constructor === foo
);

答案 1 :(得分:0)

要回答第二个问题:

  

该原型对象具有自己的原型...

如果您实际看一下原型的多个级别及其在实践中的工作方式,那么理解这个概念会更容易:

function ClassA() {
  this.a = 1;
}
ClassA.prototype.getA = function(){
  return this.a;
};

function ClassB() {
  this.b = 2
}
ClassB.prototype = new ClassA();
ClassB.prototype.getB = function(){
  return this.b;
};

var b = new ClassB();
console.log(b.getA());
> 1
console.log(b.getB());
> 2

现在您会注意到,在定义类(函数)时,我们扩展(或添加)了prototype。但是,当我们查看类的实例(在我的示例中为b)时,没有prototype;它被称为__proto__,如@CertainPerformance所述)。因此,查看b的原型链,您将看到:

b.__proto__
> ClassA {a: 1, getB: ƒ}
b.__proto__.__proto__
> {getA: ƒ, constructor: ƒ}
b.__proto__.__proto__.__proto__
> {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
b.__proto__.__proto__.__proto__.__proto__
> null

因此,当您键入b.getB()时,JavaScript引擎首先查看b对象中的直接属性,而看不到getB。然后,它查看b.__proto__并找到它,并完成了。

对于b.getA(),它执行相同的操作,但在第一个原型中找不到。因此它继续到b.__proto__.__proto__,并在那里找到它。

您看到的与众不同。首先,您要看一个函数的prototype,并看到其中包含另一个名为constructor的函数。并且由于constructor也是一个函数,因此它内部有一个prototype。等等,直到永远。但是是构造函数的原型,不是是原始函数/对象的原型链的一部分。