85

JavaScript 1.8.5(ECMAScript 5)は、さまざまな程度の徹底性で、渡されたオブジェクトの将来の変更を防ぐいくつかの興味深いメソッドを追加します。

おそらく、これらの主なポイントは間違いを見つけることです。特定のポイント以降にオブジェクトを変更したくないことがわかっている場合は、オブジェクトをロックして、後で誤って変更しようとした場合にエラーがスローされるようにすることができます。(あなたがそれをした"use strict";という条件で。)

私の質問: V8などの最新のJSエンジンでは、上記の方法を使用してオブジェクトをロックダウンすることで、パフォーマンス上の利点(たとえば、プロパティルックアップの高速化、メモリフットプリントの削減)はありますか?

John Resigのすばらしい説明も参照してください。ただし、パフォーマンスについては触れていません。)

4

7 に答える 7

97

少なくともChrome47.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ビット)のパフォーマンスに違いはありません

2017年3月6日更新: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のバグが修正されました。詳細については、JanMolakによる回答を参照してください。


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でテストを作成して確認しました。

これまでのところ、Chrome41とFirefox37でテストする機会しかありませんでした。どちらのブラウザでも、フリーズまたはシールされたオブジェクトの作成には、リテラルの作成よりも約3倍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 に答える