“锁定”的任何性能优势都可以通过“锁定”来实现。 JavaScript 对象?
JavaScript 1.8.5 (ECMAScript 5) 添加了一些有趣的方法,以不同程度的彻底性防止将来修改所传递的对象:
大概是要点其中之一是捕获错误:如果您知道在某个点之后不想修改某个对象,则可以将其锁定,这样如果您以后无意中尝试修改它,就会抛出错误。 (前提是您已经完成了“use strict”;
。)
我的问题:在现代 JS 引擎(例如 V8)中,是否有任何性能优势(例如,更快的属性)使用上述方法锁定对象时的查找、减少内存占用?
(另请参阅 John Resig 的精彩解释 – 没有提到性能,尽管。)
JavaScript 1.8.5 (ECMAScript 5) adds some interesting methods that prevent future modifications of a passed object, with varying degrees of thoroughness:
Presumably the main point of these is to catch mistakes: if you know that you don't want to modify an object after a certain point, you can lock it down so that an error will be thrown if you inadvertently try to modify it later. (Providing you've done "use strict";
that is.)
My question: in modern JS engines such as V8, is there any performance benefit (eg, faster property look-ups, reduced memory footprint) in locking down objects using the above methods?
(See also John Resig's nice explanation – doesn't mention performance, though.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
至少从 Chrome 47.0.2526.80(64 位)开始,性能没有差异。
性能测试(可在 http://jsperf.com/performance-frozen-object 获取):
< strong>更新 30.10.2019:Chrome 78.0.3904(64 位)上的性能没有差异
更新2019 年 9 月 17 日:Chrome 上的性能没有差异 76.0.3809(64 位)
2018 年 5 月 3 日更新:Chrome 上的性能没有差异< strong>66.0.3359(64 位)
更新 06.03.2017:没有区别Chrome 56.0.2924(64 位)
更新 13.12.2015 上的性能:Chrome 47.0.2526.80(64 位)上的性能没有差异-bit)
在 Chrome 34 中,在 @pimvdb 的测试用例中,冻结对象的性能略好于非冻结对象(结果如下)。然而,差异似乎不足以证明使用此技术来提高性能是合理的。
http://jsperf.com/performance-frozen-object
运行 @kangax 的测试用例表明,对象版本的性能几乎相同:
http://jsperf.com/performance-frozen-object-prop-access
http://jsperf.com/http-jsperf-com-performance-frozen-object-instanceof
There's been no difference in performance since at least Chrome 47.0.2526.80 (64-bit).
Performance test (available at http://jsperf.com/performance-frozen-object):
Update 30.10.2019: There's no difference in performance on Chrome 78.0.3904 (64-bit)
Update 17.09.2019: There's no difference in performance on Chrome 76.0.3809 (64-bit)
Update 03.05.2018: There's no difference in performance on Chrome 66.0.3359 (64-bit)
Update 06.03.2017: There's no difference in performance on Chrome 56.0.2924 (64-bit)
Update 13.12.2015: There's no difference in performance on Chrome 47.0.2526.80 (64-bit)
With Chrome 34, a frozen object performs slightly better than a non-frozen one in @pimvdb's test case (results below). The difference, however doesn't seem to be large enough to justify using this technique for performance benefits.
http://jsperf.com/performance-frozen-object
Running @kangax's test cases shows that both versions of the object perform pretty much the same:
http://jsperf.com/performance-frozen-object-prop-access
http://jsperf.com/http-jsperf-com-performance-frozen-object-instanceof
理论上,冻结对象可以让您对对象的形状做出更有力的保证。
这意味着虚拟机可以压缩内存大小。
这意味着虚拟机可以优化原型链中的属性查找。
这意味着任何活动引用都变得不活动,因为对象无法再更改。
实际上,JavaScript 引擎还没有进行这些激进的优化。
In theory freezing an object allows you to make stronger guarantees about the shape of an object.
This means the VM can compact the memory size.
It means the VM can optimize property lookups in the prototype chain.
It means any live references just became not live because the object cannot change anymore.
In practice JavaScript engines do not make these aggressive optimization yet.
更新:由于此答案最初是编写的, V8 中导致此问题的错误已得到修复。有关详细信息,请参阅 Jan Molak 的回答。
在 Google Chrome(即 V8)中,冻结对象的迭代速度比常规对象慢 98%。
http://jsperf.com/performance-frozen-object
可能是因为这些函数是相对较新,可能尚未优化(但这只是我的猜测,老实说我不知道原因)。
无论如何,我真的不建议使用它来提高性能,因为这显然没有意义。
* 测试代码为:
测试 1(非冻结对象):
测试 2(冻结对象):
Update: Since this answer was originally written, the bug in V8 that caused this issue has been fixed. See the answer by Jan Molak for more info.
In Google Chrome (so V8, that is), a frozen object iterates 98% slower than a regular object.
http://jsperf.com/performance-frozen-object
Probably this is because those functions are relatively new and probably not optimized yet (but that's just my guess, I honestly don't know the reason).
Anyhow, I really do not recommed using it for performance benefits, as that apparently does not make sense.
* The code for the test is:
Test 1 (non-frozen object):
Test 2 (frozen object):
自 2013 年 6 月 20 日起,V8 已优化 Object.freeze。自 2014 年 12 月 10 日起,V8 已优化 Object.seal 和 Object.preventExtensions。请参阅问题 https://code.google.com/p/chromium/issues/detail?id=115960
V8 has optimized Object.freeze as of Jun 20, 2013. And Object.seal and Object.preventExtensions as of Dec 10, 2014. See issue https://code.google.com/p/chromium/issues/detail?id=115960
答案中的 jsperf 链接已损坏,加上空的 for 循环可能会导致某些引擎中的死代码消除,因此我编写了一个新测试以确保不会发生代码消除。大多数情况下,冻结对象获胜:
perf.link benchmark
作为参考,代码如下所示:
编辑:我试图进一步消除死代码消除的可能性。 也许(?)引擎可以检测并消除从未读取过的未使用的
buffer
数组,因此在下面的基准测试中,我将该对象放置在globalThis对象上,并且冻结对象往往会更频繁地获胜(已编辑,最近它更频繁地获胜,但在某些时候速度较慢):perf.link 基准测试
作为参考,代码如下:
jsperf links in the answers are broken, plus an empty for-loop might cause dead code elimination in some engines, so I wrote a new test to ensure code elimination doesn't happen. Most of the time the frozen object wins:
perf.link benchmark
For reference, the code looks like:
EDIT: I tried to further eliminate the possibility of dead code elimination. Maybe (?) an engine can detect and eliminate the unused
buffer
array that is never read from, so in the following benchmark I placed the object onto the globalThis object, and the frozen object tends to win more often (edited, it more recently wins more often, but at some point it was slower):perf.link benchmark
For reference, the code looks like:
如果您对对象创建的性能感兴趣(文字、冻结、密封、
Immutable.Map
),我创建了一个 测试jsPerf 来检查一下。到目前为止,我只有机会在 Chrome 41 和 Firefox 37 中测试它。在这两种浏览器中,创建冻结或密封对象的时间比创建文字的时间大约三倍 - 而
Immutable.Map
的性能比文字差大约 50 倍。If you’re interested in the performance of object creation (literal vs frozen vs sealed vs
Immutable.Map
), I’ve created a test on jsPerf to check that out.So far I’ve only had the opportunity to test it in Chrome 41 and Firefox 37. In both browsers the creation of a frozen or sealed object takes about three times longer than the creation of a literal – whereas the
Immutable.Map
performs about 50 times worse than the literal.我在生产代码中看到这些方法的唯一原因是,出于完整性目的,您可以密封或冻结对象。
例如,我编写了一个小库,它运行得很好,并为您提供了对象中的一组方法,但我不希望您更改或覆盖我的任何属性或方法。我并不是说我可以阻止你这样做,但我可以尝试阻止你意外地这样做,这也许更重要。
此外,这些方法很容易在不了解它们的环境中进行“填充”,只需返回原始对象即可。当然那时候就没有什么影响了。
我没有看到任何与性能相关的原因这样做。
The only reason I see for those methods in production code is, that you can have sealed or frozen objects, for integrity purposes.
For instance, I write a little library, which works just great and offers you a set of methods in an object, but I don't want to you to change or overwrite any of my properties or methods. I'm not saying I can prevent you from doing that, but I can try to prevent you do it by accident which maybe is more important.
Also, those methods are easy to 'shim' in environment which doen't know about them, by just returning the original object. Of course it would have no effect then.
I don't see any performance related reasons to do this.