Google Chrome:シーケンス外で評価されたJavaScript連想配列
-
22-07-2019 - |
質問
Ok、それでウェブページで、私は連想配列として使用しているJavaScriptオブジェクトを持っています。これは、ページの読み込み時にスクリプトブロックに静的に存在します。
var salesWeeks = {
"200911" : ["11 / 2009", "Fiscal 2009"],
"200910" : ["10 / 2009", "Fiscal 2009"],
"200909" : ["09 / 2009", "Fiscal 2009"],
"200908" : ["08 / 2009", "Fiscal 2009"],
"200907" : ["07 / 2009", "Fiscal 2009"],
"200906" : ["06 / 2009", "Fiscal 2009"],
"200905" : ["05 / 2009", "Fiscal 2009"],
"200904" : ["04 / 2009", "Fiscal 2009"],
"200903" : ["03 / 2009", "Fiscal 2009"],
"200902" : ["02 / 2009", "Fiscal 2009"],
"200901" : ["01 / 2009", "Fiscal 2009"],
"200852" : ["52 / 2008", "Fiscal 2009"],
"200851" : ["51 / 2008", "Fiscal 2009"]
};
オブジェクトを次のようなHTML選択ボックスに変換するため、キー/値のペアの順序は意図的です。
<select id="ddl_sw" name="ddl_sw">
<option value="">== SELECT WEEK ==</option>
<option value="200911">11 / 2009 (Fiscal 2009)</option>
<option value="200910">10 / 2009 (Fiscal 2009)</option>
<option value="200909">09 / 2009 (Fiscal 2009)</option>
<option value="200908">08 / 2009 (Fiscal 2009)</option>
<option value="200907">07 / 2009 (Fiscal 2009)</option>
<option value="200906">06 / 2009 (Fiscal 2009)</option>
<option value="200905">05 / 2009 (Fiscal 2009)</option>
<option value="200904">04 / 2009 (Fiscal 2009)</option>
<option value="200903">03 / 2009 (Fiscal 2009)</option>
<option value="200902">02 / 2009 (Fiscal 2009)</option>
<option value="200901">01 / 2009 (Fiscal 2009)</option>
<option value="200852">52 / 2008 (Fiscal 2009)</option>
<option value="200851">51 / 2008 (Fiscal 2009)</option>
</select>
...次のようなコード(関数から抜粋):
var arr = [];
arr.push(
"<select id=\"ddl_sw\" name=\"ddl_sw\">" +
"<option value=\"\">== SELECT WEEK ==</option>"
);
for(var key in salesWeeks)
{
arr.push(
"<option value=\"" + key + "\">" +
salesWeeks[key][0] + " (" + salesWeeks[key][1] + ")" +
"<\/option>"
);
}
arr.push("<\/select>");
return arr.join("");
これはすべてIE、FireFox、Operaで正常に動作します。
ただし、Chromeでは、順序がすべて奇妙になります:
<select id="ddl_sw" name="ddl_sw">
<option value="">== SELECT WEEK ==</option>
<option value="200852">52 / 2008 (Fiscal 2009)</option>
<option value="200908">08 / 2009 (Fiscal 2009)</option>
<option value="200906">06 / 2009 (Fiscal 2009)</option>
<option value="200902">02 / 2009 (Fiscal 2009)</option>
<option value="200907">07 / 2009 (Fiscal 2009)</option>
<option value="200904">04 / 2009 (Fiscal 2009)</option>
<option value="200909">09 / 2009 (Fiscal 2009)</option>
<option value="200903">03 / 2009 (Fiscal 2009)</option>
<option value="200905">05 / 2009 (Fiscal 2009)</option>
<option value="200901">01 / 2009 (Fiscal 2009)</option>
<option value="200910">10 / 2009 (Fiscal 2009)</option>
<option value="200911">11 / 2009 (Fiscal 2009)</option>
<option value="200851">51 / 2008 (Fiscal 2009)</option>
</select>
注:この順序は、奇妙ですが、以降の更新では変わりません。常にこの順序です。
では、Chromeは何をしていますか?ループの処理方法の最適化?
そもそも、キー/値のペアが any 連想配列で宣言されている順序に依存するのは間違っていますか?
これまで疑問に思ったことはありません。このテクニックは他のブラウザでも常に機能していたため、順序が成り立つと思いました。しかし、順序が保証されていることをどこにも述べていなかったと思います。たぶんそうじゃない?
どんな洞察も素晴らしいでしょう。 ありがとう。
解決
すべてのキーと値のペアが配置される紙袋として連想配列を考えます。 (for ... inループなどで)ペアを見るために袋に手を入れると、それらに遭遇する順序はすべての実用的な目的でランダムになります。
特定の順序で表示したい場合は、キーを配列に抽出して並べ替える必要があります。次に、出会ったキーを使用して連想配列にインデックスを付けて、配列を調べます。
他のヒント
連想配列に要素が格納される順序は保証されていません。出力を明示的にソートする必要があります。
他の回答が言うように、主要なブラウザはすべて定義された順序で繰り返しますが、オブジェクトのプロパティが繰り返される順序は仕様で定義されていません。
Chromeは、オブジェクトのすべてのプロパティにプリミティブ値が含まれている場合、それらも順番に列挙します。 John Resigが、Chromeの動作について詳しく説明しています(「for for order order」の下): http://ejohn.org/blog/javascript-in-chrome/
指摘したように、Chromeの動作は完全に有効です。
これは、オブジェクト指向の考え方が役立つ場合の良い例です。連想配列またはオブジェクトのリストだけが本当に必要ですか?
var salesWeeks = [
["200911", "11 / 2009", "Fiscal 2009"],
...
]
...
for(var key in salesWeeks)
{
arr.push(
"<option value=\"" + salesWeeks[key][0] + "\">" +
salesWeeks[key][1] + " (" + salesWeeks[key][2] + ")" +
"<\/option>"
);
}
より良いサービスを提供します(何らかのソートを提唱した人には、順序はすでに定義されています-なぜ余分な作業をしたいのですか?)
@curtainDog:いいえ!いや! JavaScriptのArrayオブジェクトで「for .. in」を使用するのは良くありません。ここでのほとんどの応答のポイントは、「for .. in」は順序を保証しないということです。さらに、「for .. in」はオブジェクトのコンストラクターのプロトタイプからプロパティを取得し、存在しないキーを反復処理しません。
@Samnan:仕様では、反復順序は保証されていないと単純に述べています。つまり、ブラウザは、ソートされた順序、挿入の順序、ランダムな順序、またはその他の方法で自由に反復できます。ハッシュテーブルのようなものです-偶然出現したとしても、ランダムと考えてください。
ほとんどのブラウザは、配列オブジェクトを使用して「for..in」を探し、数値の順序で繰り返し処理することで問題が発生しないようにします。ただし、そのように使用するほとんどの人が実際に行っているとは思わないので、オブジェクトタイプの反復が特に必要でない限り、避けるべきです。
これは実際のグッドプラクティスではありませんが...
値にスペースを追加すると、クロムは値を数値と見なさず、値でソートしません。
例:
<select>
<option value=" 3">Third</option>
<option value=" 1">First</option>
<option value=" 2">Second</option>
</select>
良い面は、誰かが提案したようにIDからアルファベット文字を追加してから削除する必要がないことです(この質問または同様の質問を持つ他の投稿で覚えていないでください)、ほとんどの場合、それを簡単にトリミングできますスペースは無視され、それらを別のファイルに投稿または取得すると、スペースではなく整数値が表示されます。
他のすべての答えに反して、それは確かにクロムのバグです
理由:
データ構造がバリーのような紙袋の場合:
値は常にランダム化する必要があります。これはクロムの場合ではありません
データ構造がシーケンシャルの場合:
値は、構造に追加される順序である必要があります
他のブラウザーは2番目のアプローチに従いますが、chromeはどちらにも従わず、chromeがアクセス中にchromeがデータ構造をどのようにソートするかについての説明はまだありません。