难以手动走原型链

And*_*rew 6 javascript constructor prototype

我想尝试手动走几个对象的原型链,只是为了看看我在路上找到了什么.但是,我遇到了我尝试过的第一个问题.这是代码:

function MyObject() { }
var x = new MyObject();
console.log('--------------------------------------------');
console.log('x.constructor.name: ' + x.constructor.name);
console.log('x.constructor.prototype.constructor.name: ' + x.constructor.prototype.constructor.name);
console.log(x.constructor.prototype === Function.prototype ? 'Good guess.' : 'No, you are wrong.');
console.log(x.constructor === MyObject ? 'Good guess.' : 'No, you are wrong.');
console.log('--------------------------------------------');
Run Code Online (Sandbox Code Playgroud)

上面的代码会在Google Chrome的开发人员工具控制台中生成以下输出:

--------------------------------------------
x.constructor.name: MyObject
x.constructor.prototype.constructor.name: MyObject
No, you are wrong.
Good guess.
--------------------------------------------
Run Code Online (Sandbox Code Playgroud)

x的构造函数是MyObject函数是有道理的,因为x是使用MyObject上的new关键字实例化的(这取决于构造函数的定义).因此,我理解输出的第一行(注意:我开始计算从零起的输出行).然而,第二行让我感到困惑.我想知道MyObject的原型是什么.显然,它不是Function类型的对象,如输出的第3行所示,它告诉我我错了.第四行输出只是加强了第一行的输出.

更一般地说,我假设走一个对象的原型链的正确方法是从有问题的对象转到它的构造函数,然后从构造函数到构造函数的原型,假设最后一个引用不是空值.我假设应该重复这个两步过程(包括转到构造函数,然后转到构造函数的原型),直到从构造函数到原型的null引用,从而表示原型链的结束.但是,这似乎不起作用,因为将此算法应用于上述场景只会导致循环引用.

总之,我有两个问题:

  1. 为什么x.constructor === x.constructor.prototype.constructor(换句话说,为什么循环引用),以及什么样的对象是x.constructor.prototype,无论如何(或者,换句话说,如何它是否实例化/它来自哪里)?
  2. 为了正确地遍历对象x的原型链,如何校正上述算法?

编辑

我在这里遇到了关于StackOverflow的类似问题,但它没有明确地询问走原型链的正确方法.它确实指出了循环引用,但......

rad*_*aph 5

在 Javascript 术语中,对象a的“原型”是指从中a继承属性的对象。访问它的基于标准的方法是Object.getPrototypeOf

var protoOfA = Object.getPrototypeOf(a);
Run Code Online (Sandbox Code Playgroud)

还有旧的方式,非标准但被一些浏览器支持:

var protoOfA = a.__proto__;
Run Code Online (Sandbox Code Playgroud)

但是,如果您有一个函数 F,F.prototype则不会引用F从中继承任何内容的对象。相反,它指的是F 创建的实例所继承的对象:

function F() {};
a = new F();
console.log(Object.getPrototypeOf(a) === F.prototype); // true
Run Code Online (Sandbox Code Playgroud)

当您定义一个函数时,会创建一个对象作为该函数创建的实例的原型,并且这个新对象存储在该函数的prototype属性中。

——

函数在很多方面表现得像对象(例如,它们可以有属性),但它们并不完全像其他对象:

console.log(typeof a); // "object"
console.log(typeof F); // "function"
Run Code Online (Sandbox Code Playgroud)

他们的“原型”定义不明确(示例在 Chrome 中运行)(这显然是Chrome 特定的行为

console.log(Object.getPrototypeOf(F)); // "function Empty() {}"
console.log(Empty);                    // ReferenceError: Empty is not defined
Run Code Online (Sandbox Code Playgroud)

——

constructor 属性是奇怪。 口译员不在乎MDN 令人困惑地说

返回对创建实例原型的 Object 函数的引用。

此外,您可以更改 constructor 对象上的值,但这对对象是什么或它的行为方式没有影响——它只是描述性的。

——

所以,回答你的问题:

为什么是 x.constructor === x.constructor.prototype.constructor

没有很好的理由。这是浏览器已经收敛的任意行为。

无论如何,x.constructor.prototype 是一个什么样的对象

在这个例子中, t 的x原型,与Object.getPrototypeOf(x). 但总的来说,你不能依赖它x.constructor或从它派生任何东西,因为它是任意的。

为了正确地遍历对象 x 的原型链,如何更正上述算法?

for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) {
  // do something with p
}
Run Code Online (Sandbox Code Playgroud)