如https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access中的示例,我(试图)理解对象的属性是基于隐藏类存储的,称为其构造函数“C [N]”。我可能没有正确理解它......例如:
// Let's suppose Object has these hidden classes already
/* Object[[HiddenClasses]] > C0, C1, C2
*
* C0 - for "x", goto C1
* C1 - "x"; for "y", goto C2
* C2 - "x", "y";
*/
var obj = {
x: 0
};
// Currently based in C1 to get/put properties
obj.y = 0;
// Now based in C2
1。如果这个新对象添加了一个新属性会发生什么?
obj.z = 0
它的行为是否仍然像Object
的第一个实例?
2。如果同一构造函数的对象以隐藏类的相反顺序添加属性会发生什么?
({ y: 5; }); // Will this be based in C2?
3。删除属性会发生什么?它的值是否仅在内存中更改以表示deleted
?
4。当编译器无法看到其计算属性访问的对象或名称时,是否在隐藏类中完成查找?即:
({ [Math.random()]: 0 }),
randomlyReceivedObject.property;
答案 0 :(得分:2)
在obj.z = 0
之后,C2
获得了新的转化for "z", goto C3
,并为该对象创建了新的隐藏类C3 - "x", "y", "z"
。
该对象将有一个新的隐藏类C4 - "y"
。 C0
获得了新的转换:for "y", goto C4
。如果该对象稍后获得“x”属性,则会创建一个新的隐藏类C5 - "y", "x"
,并在C4
:for "x", goto C5
中进行转换。 C5
和C2
将永远保持不同。这实际上是由JavaScript规范强制执行的,因为例如一个 for..in
循环Object.getOwnPropertyKeys
必须按创建顺序迭代属性,V8通过隐藏类跟踪属性创建顺序。
由于拥有更多隐藏类自然会产生速度和内存成本,因此通常建议始终以相同的顺序创建属性(例如,通过使用构造函数)。
删除属性后,对象将进入字典模式,并且不再使用隐藏类来跟踪其属性。在内部,这是通过一个特殊的隐藏类实现的:C6 - all properties are in the properties dictionary
。然后,每个后续属性访问都需要字典查找。如果要避免这种情况,可以手动覆盖属性而不是删除它们:obj.x = null
或类似的。 (精细打印:从最近的V8版本开始,有一个例外,如果 last 属性被删除,那么最后隐藏的类转换将被回滚。此实现细节可能会也可能不会将来坚持下去,所以不要依赖它。)
隐藏类始终用于查找。内联缓存只是缓存这些查找的结果;这总是在执行时发生,而不是在编译时发生。 “编译器”通常不能“看到”对象,因为在编译时还没有对象。