在这种情况下,扩展原型链如何提高性能?

How does extending the prototype chain increase performance in this case?

我长期以来一直认为深度 prototype chains resulted in performance deterioration for property accessors. I was trying to explain that on when a quick benchmark I threw together 导致的结果与我的预期完全相反。

这是怎么回事?我是否遗漏了一些明显的东西,或者这是否完全表明我(和其他人)对 prototype 链上 属性 访问器的性能的假设是错误的?

设置

const object1 = {
  foo: 'Hello, World!',
  get bar () { return this.foo }
};

const object2 = Object.assign(Object.create({
  get bar () { return this.foo }
}), {
  foo: 'Hello, World!'
});

let result;

测试 1

(对照,无prototype

result = object1.bar;

测试 2

(实验,prototype

result = object2.bar;

结果

测试 1 运行 比测试 2 慢 92.85%,这意味着将 get bar () {} 放在 prototype 链中而不是对象自身的属性中会导致速度提高 14 倍属性 访问器。请参阅 Object.create() 以了解对象的布局有何不同。

测试 1

79,323,722 ops/s ±0.34%

测试 2

1,108,762,737 ops/s ±0.15%

在 Windows 10 Intel i7-7700K CPU @ 4.20GHz 使用 Google Chrome 63.0.3239.132(官方构建)(64 位)

据我所知,这些细节仅适用于 V8 引擎,我不确定这如何直接映射到 Firefox 的实现。

如果没有原型,V8 会创建隐藏的 classes 来支持对象的属性。对于每个新的属性,都会创建一个新的隐藏class,然后会创建一个从之前的隐藏class到新隐藏

的过渡。

但是,这不会发生在原型上,这是我就该主题进行的对话中鲜为人知的事实。换句话说,是的,原型 更快。

To optimize prototypes, V8 keeps track of their shape differently from regular transitioning objects. Instead of keeping track of the transition tree, we tailor the hidden class to the prototype object, and always keep it fast -Toon Verwaest (V8 dev)

此设置全部发生在 Dynamic Machine Code Generation 期间。您看到的两种设置之间的区别是更复杂的隐藏 class 路径与更自定义的路径之间的区别。或者,顾名思义,fastPropertiesWithPrototype对象和slowProperties对象的区别,后者使用的是字典模式。