在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轻松记录它们。
非常感谢。
答案 0 :(得分:5)
答案是是:将创建一个新的隐藏类。但重要的是要理解,原型对象本身将改变其隐藏类,而不是Point构造函数创建的对象。
任何对象都附加了隐藏类。让我们看一下代码
var o = new Point();
o.z = 0; // (1)
Point.prototype.zz = 0; // (2)
在任何特定时刻,任何对象都有一个隐藏的类,这意味着o
,o.__proto__
,o.__proto__.__proto__
具有与之关联的独特隐藏类。
向对象添加新属性时,它只是该对象的隐藏类才会发生变化。如果更改原型的隐藏类,则共享该原型的隐藏类对象不会更改。没有必要进行这样的更改,因为我们不希望隐藏的对象X
类完全描述其整个原型链中任何对象的布局,其隐藏类描述{{1}的布局}和X
一个人。此外,实现这种向下传播是不可行的:这需要VM维护原型和所有相关对象之间的后向链接:能够在任何时刻使对象X
枚举所有对象{{1有X
的人。
对于上面的代码,这意味着语句Y
仅更改 隐藏的Y.__proto__ === X
类和语句(1)
仅更改 o
的隐藏类(与(2)
相同的对象)但<{1}}本身的不。
此外,如果你考虑这样的代码:
Point.prototype
有时会建议这是一个性能反模式,因为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
将存储在对象外属性存储中。