请看下面例子:
let point = {};
%DebugPrint(point);
point.x = 100;
%DebugPrint(point);
point.y = 200;
%DebugPrint(point);
使用d8执行:
d8 --allow-natives-syntax test.js
得到:
DebugPrint: 0x986080c5b35: [JS_OBJECT_TYPE]
- map: 0x0986082802d9 <Map(HOLEY_ELEMENTS)> [FastProperties]
- ...
DebugPrint: 0x986080c5b35: [JS_OBJECT_TYPE]
- map: 0x098608284ce9 <Map(HOLEY_ELEMENTS)> [FastProperties]
- ...
- properties: 0x0986080406e9 <FixedArray[0]> {
#x: 100 (const data field 0)
}
DebugPrint: 0x986080c5b35: [JS_OBJECT_TYPE]
- map: 0x098608284d11 <Map(HOLEY_ELEMENTS)> [FastProperties]
- p
- ...
- properties: 0x0986080406e9 <FixedArray[0]> {
#x: 100 (const data field 0)
#y: 200 (const data field 1)
可以得到如下结论:
- 如果对象的形状没有发生改变,那么该对象就会一直使用该隐藏类;如果对象的形状发生了改变,那么 V8 会重建一个新的隐藏类给该对象。
- 因为每次为对象添加一个属性时,V8 都会为该对象重新设置隐藏类。所以,尽量使用字面量一次性初始化完整对象属性。
综上,这个文章标题的答案是 yes。
加餐:
V8 会想尽一切办法来压缩这个查找过程,以提升对象的查找效率。这个加速函数执行的策略就是内联缓存 (Inline Cache),简称为 IC。
IC 的原理很简单,直观地理解,就是在 V8 执行函数的过程中,会观察函数中一些调用点 (CallSite) 上的关键的中间数据,然后将这些数据缓存起来,当下次再次执行该函数的时候,V8 就可以直接利用这些中间数据,节省了再次获取这些数据的过程,因此 V8 利用 IC,可以有效提升一些重复代码的执行效率。
最后:
虽然我们分析的隐藏类和 IC 能提升代码的执行速度,但是在实际的项目中,影响执行性能的因素非常多,找出那些影响性能瓶颈才是至关重要的,你不需要过度关注微优化,你也不需要过度担忧你的代码是否破坏了隐藏类或者 IC 的机制,因为相对于其他的性能瓶颈,它们对效率的影响可能是微不足道的。