我有一个长期的假设,即深prototype
链导致属性登录的性能恶化。我试图在隐藏getter上解释或添加原始对象时,当我汇总在一起的快速基准时,结果与我期望的相反。
这里发生了什么?我是否错过了明显的东西,或者这完全证明了我(和其他人(关于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%
使用Google Chrome 63.0.3239.132(官方构建((64位((64位(
据我所知,这些细节仅适用于V8引擎,我不确定这是如何直接映射到Firefox的实现的。
没有原型,V8正在创建隐藏的类以支持对象的属性。对于每个新属性,都会创建一个新的隐藏类,然后创建从以前的隐藏类过渡到新类。
但是,这不是原型发生的,这是我关于该主题的对话的一个鲜为人知的事实。换句话说,是的,原型更快。
为了优化原型,V8跟踪其形状与常规过渡对象不同。我们没有跟踪过渡树,而是将隐藏类定制为原型对象,并始终保持快速-Toon verwaest(v8 dev(
此设置全部发生在动态机器代码生成期间。您看到的两个设置之间的区别是更复杂的隐藏类路径与更自定义路径之间的区别。或者,按名称,fastpropertieswithPrototype对象与慢properties对象之间的差异,后者使用字典模式。