以前の回答をさらに拡張しています...
一般的なコンパイラの観点から、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)
うまくいけば、これで十分な視覚化が得られるので、必要な処理の量が多く(または少なく)理解できます。
上記のトークンに基づいて、事実として、ARRAY_INITは常に配列を生成します。したがって、単純に配列を作成してデータを入力します。あいまいさに関する限り、字句解析ステージでは、ARRAY_INITがオブジェクトプロパティアクセサー(例:)obj[foo]
または文字列/正規表現リテラル内のブラケット(例: "foo [] bar"または/ [] /)とすでに区別されています。
これはごくわずかですが、でより多くのトークンを使用することもできますnew Array
。さらに、単に配列を作成したいだけであることはまだ明確ではありません。「新しい」トークンが表示されますが、「新しい」何ですか?次に、新しい「配列」が必要であることを示すIDENTIFIERトークンが表示されますが、JavaScript VMは通常、IDENTIFIERトークンと「ネイティブグローバルオブジェクト」のトークンを区別しません。したがって...
IDENTIFIERトークンに遭遇するたびに、スコープチェーンを検索する必要があります。Javascript VMには、「arguments」オブジェクト、ローカルで定義された変数などを含む可能性がある各実行コンテキストの「Activationオブジェクト」が含まれています。Activationオブジェクトで見つからない場合は、グローバルスコープに到達するまでスコープチェーンの検索を開始します。 。何も見つからない場合は、をスローしReferenceError
ます。
変数宣言を見つけたら、コンストラクターを呼び出します。 new Array
暗黙の関数呼び出しであり、経験則では、実行中の関数呼び出しの速度が遅くなります(そのため、静的C / C ++コンパイラーが「関数のインライン化」を許可する理由-SpiderMonkeyなどのJS JITエンジンがオンザフライで実行する必要があるため)
Array
コンストラクタはオーバーロードされます。Arrayコンストラクターはネイティブコードとして実装されるため、パフォーマンスが向上しますが、引数の長さを確認し、それに応じて動作する必要があります。さらに、引数が1つだけ指定された場合は、引数の型をさらに確認する必要があります。new Array( "foo")は["foo"]を生成し、ここでnew Array(1)は[undefined]を生成します
つまり、すべてを単純化するために、配列リテラルを使用すると、VMは配列が必要であることを認識します。でnew Array
、VMはnew Array
実際に何が行われるかを理解するために追加のCPUサイクルを使用する必要があります。