222

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

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

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

そして、私はさらにそれらを次のように使用します。

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

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

4

10 に答える 10

229

ジョン・レシグの引用

現在、すべての主要なブラウザは、オブジェクトのプロパティを定義された順序でループします。いくつかの場合を除いて、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"

これの専門性は、これがいつでも変更される可能性があるという事実ほど重要ではありません。このままでいることに依存しないでください。

つまり、順序が重要な場合は配列を使用します。

于 2008-11-11T13:24:20.847 に答える
54

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

それは2012年であり、主要なブラウザはまだ異なります。

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] 
于 2012-01-02T19:02:21.573 に答える
28

ECMAScript Language Specificationのセクション 12.6.4 (for .. inループ上) から:

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

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

これは、それぞれがプリミティブ値、オブジェクト、または関数を含むプロパティの順不同のコレクションです。オブジェクトのプロパティに格納された関数をメソッドと呼びます。

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

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

于 2008-11-11T12:14:34.357 に答える
10

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

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

于 2008-11-11T12:14:15.277 に答える
5

プロパティの削除に関しても反復順序が混乱しますが、この場合は 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での議論が何らかの兆候である場合、仕様を変更して反復順序を修正したいという要望は、開発者の間で非常に人気があるようです。

于 2011-01-04T07:44:04.447 に答える
3

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

于 2008-12-08T19:49:54.513 に答える
3

注文は信頼できません。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 を示しています。

于 2010-08-25T14:57:34.677 に答える
2

他の回答で述べたように、いいえ、順序は保証されません。

順番に繰り返したい場合は、次のようにすることができます。

let keys = Object.keys(myObject);
for (let key of keys.sort()) {
  let value = myObject[key];
  
  // Do what you want with key and value 
}

パフォーマンスの観点から、これは最適ではないことに注意してください。

于 2020-08-11T09:30:56.117 に答える