array.pushがarray[n] = valueより速い場合があるのはなぜですか?
質問
あるコードをテストした副次的な結果として、私は小さな関数を書きました。
array.push(value)
メソッドと直接アドレス指定
array[n] = value
. 驚いたことに、特にFirefoxや時にはChromeでは、プッシュメソッドの方が高速であることがしばしば示されました。好奇心だけですが、どなたかこの現象について説明できる方はいらっしゃいますか?
あなたは、テスト@を見つけることができます
このページ
(クリック '配列法の比較')
どのように解決するのですか?
様々な要因が絡んできますが、ほとんどのJSの実装では、後で必要になった場合にスパースストレージに変換されるフラット配列を使用しています。
基本的に、スパースになるという決定は、どの要素が設定されているか、そしてフラットのままではどれだけのスペースが無駄になるかに基づいたヒューリスティックなものです。
あなたのケースでは、最後の要素を最初に設定しています。これは、JSエンジンが、長さが
n
の長さを必要とする配列が、単一の要素だけであることを意味します。 もし
n
が十分に大きい場合、これは即座に配列をスパース配列にします -- ほとんどのエンジンでは、これはその後のすべての挿入が遅いスパース配列のケースを取ることを意味します。
インデックス0からインデックスn-1まで配列を埋める追加のテストを追加すべきです -- それははるかに、はるかに速くなるはずです。
Christophへの返答と、先延ばしにしたい欲求から、JSで配列が(一般的に)どのように実装されるかについて説明します--明細はJSエンジンによって異なりますが、一般原則は同じです。
すべてのJS
Object
であるため、文字列、数値、true、false ではありません。
undefined
または
null
) は基本オブジェクト型を継承します -- 正確な実装は様々で、C++継承であったり、Cで手動であったりします(どちらの方法でも利点はあります) -- 基本オブジェクト型はデフォルトのプロパティアクセスメソッドを定義します、例.
interface Object {
put(propertyName, value)
get(propertyName)
private:
map properties; // a map (tree, hash table, whatever) from propertyName to value
}
このObject型は、すべての標準的なプロパティアクセスロジック、プロトタイプチェーンなどを処理します。 そして、Arrayの実装は次のようになります。
interface Array : Object {
override put(propertyName, value)
override get(propertyName)
private:
map sparseStorage; // a map between integer indices and values
value[] flatStorage; // basically a native array of values with a 1:1
// correspondance between JS index and storage index
value length; // The `length` of the js array
}
さて、JSでArrayを作成すると、エンジンは上記のデータ構造のようなものを作成します。 Array インスタンスにオブジェクトを挿入すると、Array の put メソッドは、プロパティ名が 0 から 2^32-1 (または 2^31-1 かもしれませんが、正確には忘れました) の間の整数 (または、 "121", "2341" など、整数への変換が可能) かどうかをチェックします。 もしそうでなければ、putメソッドはベースとなるObjectの実装に転送され、標準的な[[Put]]ロジックが実行されます。 もしデータが十分にコンパクトであれば、エンジンはフラット配列ストレージを使用し、その場合、挿入(および取得)は単に標準的な配列インデックス操作になります。
正直なところ、現在、どの JS エンジンも、その変換が発生した後にスパース ストレージからフラット ストレージに変換しているかどうかはわかりません。
とにかく、これは何が起こるかのかなりハイレベルな概要であり、より厄介な詳細の多くを省きますが、これが一般的な実装パターンです。 追加のストレージ、および put/get がどのようにディスパッチされるかの詳細は、エンジンによって異なりますが、これが私が設計と実装を本当に説明できる最も明確なものです。
細かい追加点ですが、ES仕様では
propertyName
を文字列として参照していますが、JSエンジンは整数のルックアップにも特化する傾向があるので、そのため
someObject[someInteger]
は整数のプロパティを持つオブジェクトを見ている場合、整数を文字列に変換しません。 例えば、配列、文字列、DOM 型 (
NodeList
など)。
関連
-
[解決済み] JavaScript で配列に値が含まれているかどうかを確認するにはどうすればよいですか?
-
[解決済み] B "の印刷が "#"の印刷より劇的に遅いのはなぜですか?
-
[解決済み] Javaで配列に特定の値が含まれているかどうかを判断するにはどうすればよいですか?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] 配列を値でコピーする
-
[解決済み] 配列の反復処理に "for...in "を使用するのは、なぜ良くないのでしょうか?
-
[解決済み] <は<=より速いのか?
-
[解決済み】オブジェクトの配列を文字列のプロパティ値でソートする
-
[解決済み] BlobからArrayBufferへ移行する方法
-
[解決済み] TypeScriptプロジェクトで既存のC#クラス定義を再利用する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] JavaScriptで次の要素/前の要素を取得しますか?
-
[解決済み] チェックボックスが選択されているかどうかを確認するjQuery
-
[解決済み] URL/アドレスバーからJavascriptの関数を呼び出す
-
[解決済み] WebStormで未解決の変数が大量にある場合の警告に対処する方法は?
-
[解決済み] アサインの左側にJavascriptのオブジェクトブラケット表記({ ナビゲーション } =)があります。
-
[解決済み] JavaScriptのtoString()関数をオーバーライドして、デバッグ用に意味のある出力を提供することは可能でしょうか?
-
[解決済み] JavaScript のオブジェクトの配列を比較し、最小値/最大値を取得する
-
[解決済み] Chromeのwebkitインスペクタで「Unsafe JavaScript attempt to access frame with URL...」というエラーが継続的に発生する。
-
[解決済み] Javascriptの配列は疎なのか?
-
Array関数のJavaScript実行時の複雑さ