如果我们创建新的原型属性,对象会改变它的隐藏类吗?

Will the object change its hidden class if we create new prototype properties?

本文关键字:隐藏 改变 创建 我们 原型 如果 属性 对象      更新时间:2023-09-26

在V8中,当添加新属性时,对象会更改其隐藏类。

function Point(x, y) {
  this.x = x; // This will create new hidden class
  this.y = y; // This too
}

我的问题很简单,这会创建一个新的隐藏类吗?

Point.prototype.z = null;
我问这个问题是因为在我读过的编码风格指南中,他们说我们应该通过创建原型来声明类属性,而不是在构造函数中分配它们。这也将帮助我们轻松地用JSDoc记录它们。

答案是:一个新的隐藏类将被创建。然而,重要的是要理解,将改变其隐藏类的是原型对象本身,而不是Point构造函数创建的对象。

任何对象都有一个附加的隐藏类。让我们看一下代码

var o = new Point();
o.z = 0;  // (1)
Point.prototype.zz = 0;  // (2)

在任何给定时刻,任何对象都有一个隐藏类,这意味着o, o.__proto__, o.__proto__.__proto__有一个与它们相关联的独特的隐藏类。

当你给对象添加一个新属性时,改变的只是该对象的隐藏类。如果你改变了原型的隐藏类,共享原型的对象的隐藏类不会改变。由于我们不期望对象X的隐藏类完全描述其整个原型链中任何对象的布局,因此不需要进行这样的更改,其隐藏类仅描述XX的布局。此外,实现这种向下传播是不可行的:这将要求VM在原型和所有相关对象之间保持向后链接:能够在任何时候为对象X枚举具有Y.__proto__ === X的所有对象Y

对于上面的代码,这意味着语句(1)只更改了 o的隐藏类,语句(2)只更改了 Point.prototype的隐藏类(与o.__proto__是同一个对象),而不更改o本身的

此外,如果您考虑这样的代码:

Point.prototype.z = 0;  // Initial value
var o1 = new Point();
o1.z = 11;  // (3)
var o2 = new Point();

有时被推荐,这是一个性能反模式,因为o1/o2Point.prototype的隐藏类是断开连接的。在(3)赋值会改变o1的隐藏类,即使o1.__proto__已经有了属性z。对象o1o2将最终具有不同的隐藏类,这将导致所有使用它们的代码都多态并惩罚性能。此外,o1最终会比在构造函数中添加z使用更多的空间,因为z将存储在对象外属性存储中。