如果我们创建新的原型属性,对象是否会更改其隐藏的类?

时间:2014-08-04 02:40:17

标签: javascript prototype v8 internals

在V8中,当添加新属性时,对象会更改其hidden class

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

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

Point.prototype.z = null;

我问这个问题是因为在我读过的编码风格指南中,他们说我们应该通过创建原型来声明类属性,而不是在构造函数中赋值。这也有助于我们使用JSDoc轻松记录它们。

非常感谢。

1 个答案:

答案 0 :(得分:5)

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

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

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

在任何特定时刻,任何对象都有一个隐藏的类,这意味着oo.__proto__o.__proto__.__proto__具有与之关联的独特隐藏类。

向对象添加新属性时,它只是该对象的隐藏类才会发生变化。如果更改原型的隐藏类,则共享该原型的隐藏类对象不会更改。没有必要进行这样的更改,因为我们不希望隐藏的对象X类完全描述其整个原型链中任何对象的布局,其隐藏类描述{{1}的布局}和X一个人。此外,实现这种向下传播是不可行的:这需要VM维护原型和所有相关对象之间的后向链接:能够在任何时刻使对象X枚举所有对象{{1有X的人。

对于上面的代码,这意味着语句Y仅更改 隐藏的Y.__proto__ === X类和语句(1)仅更改 o的隐藏类(与(2)相同的对象)但<{1}}本身的

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

Point.prototype

有时会建议这是一个性能反模式,因为o.__proto__ / oPoint.prototype.z = 0; // Initial value var o1 = new Point(); o1.z = 11; // (3) var o2 = new Point(); 的隐藏类是断开连接的。即使o1已经拥有属性o2Point.prototype处的分配也会更改隐藏的(3)类。对象o1o1.__proto__将最终具有不同的隐藏类,这将导致使用它们的所有代码变为多态并惩罚性能。此外,z最终将使用比在构造函数中添加o1的情况更多的空间,因为o2将存储在对象外属性存储中。