web-dev-qa-db-ja.com

「for(…in…)」ループ内の要素の順序

Javascriptの「for…in」ループは、宣言された順序でハッシュテーブル/要素をループしますか?順番に実行しないブラウザはありますか?
使用するオブジェクトはonceと宣言され、変更されません。

私が持っていると仮定します:

var myObject = { A: "Hello", B: "World" };

そして、私はそれらをさらに以下で使用します:

for (var item in myObject) alert(item + " : " + myObject[item]);

適切なブラウザのほとんどで、「A: "Hello"」が常に「B: "World"」の前に来ることを期待できますか?

194
chakrit

John Resigの引用

現在、すべての主要なブラウザーは、定義された順序でオブジェクトのプロパティをループします。いくつかの場合を除き、Chromeもこれを行います。 [...]この動作は、ECMAScript仕様では明示的に未定義のままです。 ECMA-262のセクション12.6.4:

プロパティを列挙する仕組みは...実装に依存します。

ただし、仕様は実装とはまったく異なります。 ECMAScriptの最新の実装はすべて、定義された順序でオブジェクトプロパティを反復処理します。このため、Chromeチームはこれをバグと見なしており、修正する予定です。

すべてのブラウザは、定義順序を尊重します Chromeを除く およびOperaは、すべての非数値プロパティ名に対して実行します。これらの2つのブラウザでは、プロパティは最初の非数値プロパティの前に順番にプルされます(これは、配列の実装方法に関係しています)。 Object.keysの順序も同じです。

この例では、何が起こるかを明確にする必要があります。

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

この技術は、いつでも変更される可能性があるという事実ほど重要ではありません。このようにとどまるものに頼らないでください。

要するに:順序が重要な場合は配列を使用します。

204
Borgar

1年後にこれをぶつける...

2012であり、主要なブラウザstillは異なります:

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.Push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

要旨 または 現在のブラウザでテスト

Safari 5、Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21、Opera 12、Node 0.6、Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
54
dvdrtrgn

ECMAScript言語仕様 のセクション12.6.4(for .. inループ上)から:

プロパティを列挙するメカニズムは実装に依存します。列挙の順序はオブジェクトによって定義されます。

セクション4.3.3(「オブジェクト」の定義):

これは、プロパティの順不同のコレクションであり、各プロパティにはプリミティブな値、オブジェクト、または関数が含まれています。オブジェクトのプロパティに格納されている関数は、メソッドと呼ばれます。

つまり、JavaScript実装全体で一貫した順序で列挙されているプロパティに依存できないことを意味します。 (とにかく実装固有の言語の詳細に依存するのは悪いスタイルでしょう。)

順序を定義する場合は、オブジェクトにアクセスする前にソートするキーの配列など、順序を定義するものを実装する必要があります。

26
Tomalak

列挙/列挙するオブジェクトの要素は、DontEnumフラグが設定されていないプロパティです。 ECMAScript(別名Javascript)は、「オブジェクトは順序付けられていないプロパティのコレクションです」と明示的に述べています( http://www.mozilla.org/js/language/E262-3.pdf セクション8.6を参照してください) )。

すべてのJavascript実装が宣言順に列挙されると想定することは、標準に準拠していません(つまり安全です)。

10
Adam Wright

反復順序もプロパティの削除に関して混乱しますが、この場合はIEのみです。

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

http://code.google.com/p/v8/issues/detailでの議論の場合、仕様を変更して反復順序を修正したいという要望は、開発者の間で非常に人気のある要望のようです。 ?id = 164 は任意の表示です。

4
Brett Zamir

iE6では、順序は保証されません。

3
Ari

注文は信頼できません。 OperaとChromeの両方は、プロパティのリストを順不同で返します。

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

上記のコードでは、OperaにB、A、C、ChromeにC、A、Bが表示されています。

2
Kouber Saparev