为什么Object.prototype的__proto__,另一个Object.prototype?

Why is the __proto__ of Object.prototype, another Object.prototype?

如果我们在 chrome 控制台中创建一个数组,

arr=[1,2];

并使用arr.__proto__.__proto__检查chrome devtools中的原型链,我们得到以下结果。

如您所见,__proto__ 对象指向 null,这符合我的逻辑预期。 但是当我尝试访问原型链的同一级别时,即 Object.Prototype,通过使用 arr.__proto__,然后搜索下拉菜单,我得到了以下结果。

正如您在突出显示的行中看到的,这次 __proto__ 指向另一个 Object.Prototype。进一步打开后,我得到了与上一个命令相同的内容(查看上一张图片)。

谁能告诉我 Object.prototype 的这个额外层是如何在某些命令中创建的,而在其他命令中却没有?

P.S。我只是在学习原型继承,这是我试图了解它在 JS 环境中是如何实现的。

这是由于 Chrome 开发工具中的一个奇怪行为。 (现已弃用)__proto__ 属性 是 getter/accessor 属性,这意味着当它被访问时,它 运行 是代码的一部分。那部分代码看起来像这样:

Object.getPrototypeOf(this); // which returns this[[Prototype]]

上例中的 this 通常是您调用 .__proto__ 的对象。例如,如果你做了 arr.__proto__,那么 this 将是 arr,所以我们最终得到了预期的 arr 数组的原型。在 Chrome 开发工具控制台中,情况有些不同。而不是在像 arr 这样的对象上调用 getter,而是在您按 (...):

时手动调用它

所以现在的问题是 - 在 __proto__ getter 中手动调用 getter 中执行 Object.getPrototypeOf(this);this 的值是多少84=] 开发工具而不是通过 属性 访问权限调用它,例如 arr.__proto__?这由 Chrome 开发工具团队决定,但它的行为方式似乎是将 this 设置为最初记录的对象 1.在您的第二个示例中,该对象是 arr.__proto__。结果,getter 最终再次显示 arr.__proto__ 的原型,而不是 null.

下面的代码片段(参见 Chrome 控制台输出)是此行为的一个简单示例:

const obj = Object.create({
  get nested() {
    console.log("obj === this:", this === obj); // true
    console.log("obj[[Prototype]] === this:", this === Object.getPrototypeOf(obj)); // false
    return this;
  }
}, {
  foo: {
    value: 'bar',
    enumerable: true
  }
});

// View chrome console for output
console.log(obj);

在上面的示例中,使用 属性 {foo: "bar"} 创建了一个新对象,该对象的原型设置为具有 getter 的对象 nested() {}。此 getter returns 并记录 this 的值。当上面的代码是Chrome中的运行时,getter是在obj[[Prototype]]上点击(...)调用的(即:obj.__proto__nested 属性,你得到以下输出:

上面两个红框代表同一个对象,说明getter里面的this不是指原型对象(即:{nested: (...)})在使用 (...) 调用时,而是指最初记录的对象。与此不同,当您使用 arr.__proto__.__proto__ 时,记录的对象是 Object.prototype,因此当您调用 __proto__ getter 时,this 指的是对象 Object.prototype,其中 returns null 当它的原型被访问时。

要正确遍历原型链,您可以使用对 Object.getPrototypeOf():

的嵌套调用
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(arr))); // null

1 这只是基于一些观察的假设,但可能不正确 - 我不完全确定 chrome 如何决定设置 this 到,但需要注意的重要一点是 getter 属性 并不总是出现在其中的直接对象。