85

JavaScript 1.8.5 (ECMAScript 5) 添加了一些有趣的方法来防止将来对传递的对象进行修改,并具有不同程度的彻底性:

大概这些的主要目的是捕捉错误:如果您知道在某个点之后不想修改对象,则可以将其锁定,以便以后不经意地尝试修改它时会引发错误。(前提是你已经这样做"use strict";了。)

我的问题:在 V8 等现代 JS 引擎中,使用上述方法锁定对象是否有任何性能优势(例如,更快的属性查找、减少的内存占用)?

(另请参阅John Resig 的精彩解释——不过没有提及性能。)

4

7 回答 7

97

至少从 Chrome 47.0.2526.80(64 位)开始,性能没有差异。

Testing in Chrome 6.0.3359 on Mac OS 10.13.4
-----------------------------------------------
Test               Ops/sec
non-frozen object  106,825,468  ±1.08%  fastest
frozen object      106,176,323  ±1.04%  fastest

性能测试(可在http://jsperf.com/performance-frozen-object获得):

  const o1 = {a: 1};
  const o2 = {a: 1};

  Object.freeze(o2);

  // Non-frozen object:
  for(var key in o1);

  // Frozen object:
  for(var key in o2);

30.10.2019 更新:Chrome 78.0.3904(64 位)的性能没有差异

17.09.2019更新:Chrome 76.0.3809(64 位)的性能没有差异

03.05.2018 更新:Chrome 66.0.3359(64 位)的性能没有差异

06.03.2017 更新:Chrome 56.0.2924(64 位)的性能没有差异

13.12.2015 更新:Chrome 47.0.2526.80(64 位)的性能没有差异


使用 Chrome 34,在@pimvdb 的测试用例中,冻结对象的性能略好于非冻结对象(结果如下)。然而,差异似乎不足以证明使用这种技术来获得性能优势是合理的。

http://jsperf.com/performance-frozen-object

Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test               Ops/sec
non-frozen object  105,250,353  ±0.41%  3% slower
frozen object      108,188,527  ±0.55%  fastest

运行@kangax 的测试用例表明该对象的两个版本的性能几乎相同:

http://jsperf.com/performance-frozen-object-prop-access

Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test               Ops/sec
non-frozen object  832,133,923  ±0.26%  fastest
frozen object      832,501,726  ±0.28%  fastest

http://jsperf.com/http-jsperf-com-performance-frozen-object-instanceof

Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test               Ops/sec
non-frozen object  378,464,917  ±0.42%  fastest
frozen object      378,705,082  ±0.24%  fastest
于 2014-04-21T13:18:45.783 回答
16

从理论上讲,冻结对象可以让您对对象的形状做出更有力的保证。

这意味着 VM 可以压缩内存大小。

这意味着 VM 可以优化原型链中的属性查找。

这意味着任何活动引用都变得不活动,因为对象不能再改变了。

实际上,JavaScript 引擎还没有进行这些积极的优化。

于 2011-12-08T17:54:12.053 回答
13

更新:由于最初编写了此答案,因此已修复 V8 中导致此问题的错误。有关更多信息,请参阅Jan Molak 的答案


在 Google Chrome(即 V8)中,冻结对象的迭代速度比常规对象慢 98% 。

http://jsperf.com/performance-frozen-object

Test name*              ops/sec

non-frozen object    32,193,471
frozen object           592,726

可能这是因为这些功能相对较新,可能还没有优化(但这只是我的猜测,老实说我不知道​​原因)。

无论如何,我真的不推荐使用它来提高性能,因为这显然没有意义。


* 测试代码为:

var o1 = {a: 1};
var o2 = {a: 1};

Object.freeze(o2);

测试 1(非冷冻物体):

for(var key in o1);

测试 2(冷冻物体):

for(var key in o2);
于 2011-12-08T17:42:02.383 回答
6

V8 自 2013 年 6 月 20 日起已优化 Object.freeze。自 2014 年 12 月 10 日起,Object.seal 和 Object.preventExtensions 已优化。请参阅问题https://code.google.com/p/chromium/issues/detail?id= 115960

于 2015-03-29T15:58:53.653 回答
2

如果您对对象创建的性能感兴趣(文字 vs 冻结 vs 密封 vs Immutable.Map),我已经在 jsPerf 上创建了一个测试来检查它。

到目前为止,我只有机会在 Chrome 41 和 Firefox 37 中对其进行测试。在这两种浏览器中,创建冻结或密封对象所花费的时间大约是创建文字的三倍——而Immutable.Map性能比创建文本要差大约 50 倍。字面意思。

于 2015-05-13T20:31:44.983 回答
1

答案中的 jsperf 链接已损坏,加上空的 for 循环可能会导致某些引擎中的死代码消除,因此我编写了一个新测试以确保不会发生代码消除。大多数情况下,冻结对象获胜:

perf.link 基准测试

作为参考,代码如下所示:

const o1 = {a: 1};
const o2 = {a: 1};

Object.freeze(o2);

// store stuff to prevent any sort of theoretical dead code elimination
const buffer = [];

// test 1, unfrozen
for(const key in o1) buffer.push(key);

// test 2, frozen
for(const key in o2) buffer.push(key);

编辑:我试图进一步消除死代码消除的可能性。也许(?)引擎可以检测并消除buffer从未读取过的未使用数组,因此在以下基准测试中,我将对象放在 globalThis 对象上,冻结的对象往往会更频繁地丢失:

perf.link 基准测试

作为参考,代码如下所示:

const o1 = {a: 1};
const o2 = {a: 1};

Object.freeze(o2);

// store stuff to prevent any sort of theoretical dead code elimination
globalThis._buffer = [];

// test 1, unfrozen
for(const key in o1) globalThis._buffer.push(key);

// test 2, frozen
for(const key in o2) globalThis._buffer.push(key);
于 2021-12-27T00:02:02.517 回答
0

我在生产代码中看到这些方法的唯一原因是,出于完整性目的,您可以密封或冻结对象。

例如,我编写了一个小库,它工作得很好,并为您提供了对象中的一组方法,但我不希望您更改或覆盖我的任何属性或方法。我并不是说我可以阻止您这样做,但我可以尝试阻止您意外地这样做,这可能更重要。

此外,这些方法很容易在不了解它们的环境中“填充”,只需返回原始对象即可。那时当然不会有任何影响。

我没有看到任何与性能相关的理由来执行此操作。

于 2011-12-08T17:32:59.413 回答