JavaScript中__proto__和[[Prototype]]之间的区别

3

我阅读过并尝试理解其他类似于这个问题的答案 (像这个),但是原型继承的概念对我来说仍然不太清晰。目前最困扰我的问题是,__proto__[[ Prototype ]]之间的实际区别是什么? 就我所能理解的而言,[[ Prototype ]]是将一个对象与另一个对象"内部链接"的机制。但是当我在Youtube上看教程时会变得模糊不清,因为每当他们创建一个对象并尝试在浏览器控制台中使用console.log输出时,它都包含__proto__属性,但当我尝试做同样的事情时,输出的是[[ Prototype ]]。所以我想知道为什么会这样?"内部链接"是什么意思?提前感谢! :) 以下是在chrome中输出"[[ Prototype ]]",在firefox中输出"<prototype>"的代码。

function User(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

const user = new User("Someone", "Something");

console.log(user);


"但是当我尝试做同样的事情时,它输出[[原型]]。"请分享输出该结果的代码。 - trincot
@trincot 您好,我已经添加了一段代码片段,请检查一下! - ansme
1
我认为你特指Chrome控制台在控制台中显示对象的方式。这与JavaScript语法无关,而是控制台实现细节相关的。 - trincot
1
@trincot 是的,那就是我的意思!但是在阅读了您的答案之后,我觉得他们可能已经改变了它的表示方式,因为在我迄今为止观看的几乎每个视频中,它总是输出 __proto__ - ansme
感谢您的表述,@ansme。我确信在控制台中看到的[[prototype]]是一些新东西。我尝试过像“Chrome开发者工具中__proto__是否已更改为[[prototype]]”这样的搜索,但Google无法理解我的问题,似乎没有返回任何相关结果。 - user1063287
2个回答

4

每个对象的原型都保存在名为 [[prototype]] 的内部插槽中,而 __proto__ 只是一个 getter/setter,定义在 Object.prototype 对象中,用于获取任何对象的 [[prototype]] 内部插槽的值。

例子:

const arr = [];

数组的每个实例都会获得Array.prototype作为其原型。因此,在上面的arr声明中,[[prototype]]内部插槽包含对Array.prototype的引用,在以下表达式中:

arr.__proto__ === Array.prototype  // true

arr.__proto__从内部的[[prototype]]槽位获取Array.prototype对象。

如上所述,__proto__只是一个getter/setter,用来获取[[prototype]]内部槽位的值,并且仅作为兼容性考虑而存在。它不应在现代JavaScript代码中使用;应使用以下两种方法之一来设置/获取任何对象的原型:


还有其他内部槽位,除了[[prototype]]之外,在Ecmascript规范中也有提到,但这些内部槽位不可被我们编写的JavaScript代码访问。

如果您想了解更多关于内部槽位的信息,请阅读:

JavaScript中的“内部槽位”是什么?


这让事情更清晰了!但是你能否详细解释一下什么是“内部插槽”? - ansme
我在我的回答中包含了一个链接到另一个stackoverflow帖子,该帖子详细回答了你关于“内部插槽”的问题。 - Yousaf

4
双方括号符号来自ECMAScript规范,它始终指代一个内部实体(字段、属性、插槽等),但不能在JavaScript代码中使用。这是语言实现者的信息,有助于精确定义语言行为。
在控制台中,您可能会看到用这些双括号表示的信息,就像Chrome控制台中的情况一样。Firefox使用不同的符号:<prototype>
现在回到您的问题核心。对象与其原型对象之间的链接不是该对象的自有JavaScript属性。它是一个内部插槽

内部插槽对应于与对象关联并由各种ECMAScript规范算法使用的内部状态。内部插槽不是对象属性,也不会被继承。

你可以通过.__proto__获取原型对象,但是__proto__属性是Object.prototype对象上的getter 链接。因此这就像在循环中运行:当你写obj.__proto__时,引擎需要知道原型链是什么,才能为你找到那个__proto__值,因为它需要通过继承来获取--它不是obj本身的属性。而要找到继承链接,引擎将使用内部“插槽”[[Prototype]]

请问您能否详细解释一下“内部插槽”是什么意思?当您提到使用“__proto__”时,“像在圈子里运行”这句话我也没有理解清楚。 - ansme
1
我稍微扩展了那些段落。 - trincot
在新手语言中,可以这样说:[[prototype]]是一种特殊类型的属性,存在于所有对象上,其值是指向它直接继承的对象的链接。因为您不能直接调用[[prototype]],所以您需要使用一个特殊的方法,该方法可用于所有对象,称为.__proto__,它返回[[prototype]]的值,即它直接继承的对象。还要注意,.__proto__方法已被弃用,推荐使用getPrototypeOf() - user1063287
1
是的,那听起来很合理。只要意识到“特殊类型的属性”实际上并不是 JavaScript 术语中的属性。引擎如何维护原型链是与实现相关的。最好坚持规范的措辞,并将其称为“插槽”。其次,__proto__是一个已弃用的gettersetter - trincot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接