【问题标题】:Will the object change its hidden class if we create new prototype properties?如果我们创建新的原型属性,对象会改变它的隐藏类吗?
【发布时间】:2014-08-04 02:40:16
【问题描述】:
在 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 轻松记录它们。
非常感谢。
【问题讨论】:
标签:
javascript
prototype
v8
internals
【解决方案1】:
答案是是:将创建一个新的隐藏类。然而,重要的是要了解,将改变其隐藏类的是 prototype 对象本身,而不是由 Point 构造函数创建的对象。
任何对象都有一个附加的隐藏类。看代码
var o = new Point();
o.z = 0; // (1)
Point.prototype.zz = 0; // (2)
在任何给定时刻,任何对象都有一个隐藏类,这意味着o、o.__proto__、o.__proto__.__proto__ 具有与之关联的独特隐藏类。
当您向对象添加新属性时,只会更改该对象的隐藏类。如果您更改原型的隐藏类,则共享该原型的对象的隐藏类不会改变。没有必要进行这样的更改,因为我们不期望对象X 的隐藏类完全描述其整个原型链中任何对象的布局,它的隐藏类仅描述X 和X 的布局.此外,实现这种向下传播是不可行的:这将需要 VM 维护原型和所有关联对象之间的反向链接:能够在任何时候让对象X 枚举具有Y.__proto__ === X 的所有对象Y。
对于上面的代码,这意味着语句(1) 更改仅 o 的隐藏类和语句(2) 更改仅 @987654334 的隐藏类@(与 o.__proto__ 相同的对象)但 不是 o 本身。
此外,如果您考虑这样的代码:
Point.prototype.z = 0; // Initial value
var o1 = new Point();
o1.z = 11; // (3)
var o2 = new Point();
有时会推荐这是一种性能反模式,因为 o1 / o2 和 Point.prototype 的隐藏类是断开连接的。 (3) 的赋值将改变 o1 的隐藏类,即使 o1.__proto__ 已经具有属性 z。对象o1 和o2 最终将具有不同的隐藏类,这将导致使用它们的所有代码变为多态并降低性能。此外,o1 最终将使用比在构造函数中直接添加 z 的情况更多的空间,因为 z 将存储在对象外属性存储中。