1. ホーム
  2. javascript

[解決済み] arr = new Arrayよりarr = []の方が速いのはなぜですか?

2022-05-09 23:44:07

質問

このコードを実行したところ、以下のような結果が得られました。なぜ [] の方が速いのですか?

console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')

console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')

  • 使用 [] : 299ms
  • 使用 new : 363ms

感謝 レイノス はこちらです。 ベンチマーク このコードと、変数を定義するためのいくつかの可能な方法を示します。

解決方法は?

これまでの回答をさらに発展させると...

一般的なコンパイラの観点から、VM 固有の最適化を無視した場合。

まず、字句解析の段階で、コードをトークン化する。

例として、以下のようなトークンが生成されることがある。

[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)

これで、どの程度の処理が必要なのか、十分に視覚化できるようになったのではないでしょうか。

  1. 上記のトークンから、ARRAY_INITは常に配列を生成することが事実として分かっています。 したがって、単純に配列を作成し、それに値を入れるだけです。 曖昧さに関しては、字句解析の段階ですでにARRAY_INITとオブジェクトのプロパティアクセサ(例えば obj[foo] や、文字列/正規表現内の括弧("foo[]bar" や /[]/ など)です。)

  2. これは微々たるものですが、さらにトークンを new Array . さらに、単に配列を作りたいだけなのか、まだ完全に明確ではありません。 new"トークンがありますが、new"とは何でしょうか? IDENTIFIER トークンは、新しい "Array を作成することを意味しますが、JavaScript VM は通常、IDENTIFIER トークンと "native global objects." のトークンを区別しません。

  3. IDENTIFIER トークンに遭遇するたびに、スコープ チェーンを調べなければなりません。 Javascript VM には、各実行コンテキストに対して、quot;arguments" オブジェクトやローカル定義の変数などを含む Activation object" が含まれています。 もし、Activationオブジェクトの中に見つからない場合は、グローバルスコープに到達するまで、スコープチェーンを検索し始めます。 もし、何も見つからなければ ReferenceError .

  4. 変数宣言の場所を決めたら、コンストラクタを呼び出します。 new Array は暗黙の関数呼び出しで、関数呼び出しは実行時に遅くなるという経験則があります (静的 C/C++ コンパイラが "function inlining" を許すのはそのためで、JS JIT エンジンでは SpiderMonkey などはその場で処理しなければなりません)。

  5. その Array コンストラクタはオーバーロードされています。 Array コンストラクタはネイティブコードとして実装されているため、パフォーマンスが向上していますが、引数の長さをチェックして、それに応じて動作する必要があります。 new Array("foo") は ["foo"] を生成し、一方 new Array(1) は [undefined] を生成します。

つまり、配列リテラルを使用すると、VMは配列が必要であることを認識します。 new Array を理解するために余分な CPU サイクルを使う必要があります。 new Array 実際に が行います。