2008-11-11 127 views
174

Javascript中的「for ... in」循環是否按照它們聲明的順序通過hashtables /元素循環?是否有瀏覽器不按順序執行?
我希望使用的對象將被宣佈爲,一旦將不會被修改。「for(... in ...)」循環中的元素順序

假設我有:

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

而且我還用它們:

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

我可以期待 '答: 「你好」' 總是 ': 「世界」 B' 來之前在最合適的瀏覽器?

+59

Becasue他們只會被測試潛在的瀏覽器和變型的子集。更不用說任何未來的瀏覽器。假設一個沒有失敗的測試提供任何形式的具體證明顯然是錯誤的。 – 2008-11-11 12:23:18

+6

我懷疑自己有限的JavaScript能力會比SO人羣更好。除了誰知道什麼奇怪的瀏覽器潛藏在外?你可以在答案中看到GChrome確實存在一個在我的簡單示例中不明顯的錯誤。 – chakrit 2008-11-11 13:31:16

+0

[JavaScript保證對象屬性順序?](http://stackoverflow.com/q/5525795/1048572) – Bergi 2015-06-25 14:52:51

回答

191

Quoting John Resig

目前所有主流瀏覽器遍歷定義它們的順序對象在 屬性。除此之外,Chrome也會這樣做。 [...] ECMAScript規範顯式地將此行爲保留爲未定義。 在ECMA-262中,第12.6.4節:

枚舉屬性......的機制取決於實現。

但是,規範與實現有很大不同。 ECMAScript的所有現代實現 都按照其定義的順序迭代對象屬性。 由於這個原因,Chrome團隊認爲這是一個錯誤,將會修復它。

所有的瀏覽器都遵守定義順序with the exception of Chrome和Opera,它對每個非數字屬性名稱都有效。在這兩個瀏覽器中,屬性在第一個非數值屬性之前按順序拉動(這與他們如何實現數組有關)。 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" 

這樣做的技術性比事實,這可以在任何時候改變不那麼重要了。不要依賴這種方式。

總之:如果訂單對您很重要,請使用數組。

10

枚舉對象中的元素是沒有設置DontEnum標誌的屬性。 ECMAScript(又名Javascript)標準明確指出「一個對象是屬性的無序集合」(參見http://www.mozilla.org/js/language/E262-3.pdf第8.6節)。

假設所有Javascript實現都將按聲明順序枚舉,它不符合符合標準(即安全)的要求。

+2

這就是爲什麼他問這個問題,而不是假設:p – 2013-04-21 21:48:08

24

ECMAScript Language Specification,部分12.6.4(在for .. in環):

枚舉性能的力學是依賴於實現的。枚舉的順序由對象定義。

而且4.3.3節(的「對象」的定義):

它是屬性的無序集合的每一個包含原始值,對象或功能。存儲在對象屬性中的函數稱爲方法。

我想這意味着你不能依賴於在JavaScript實現中以一致的順序枚舉的屬性。 (依靠特定於實現的語言的詳細信息,這將是一種不好的風格。)

如果你想要定義你的訂單,你需要實現一些定義它的東西,比如你在訪問之前排序的一組鍵與它的對象。

3

在IE6中,順序不能保證。

2

訂單不可信。 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。

4

迭代次序也與刪除屬性有關,但在這種情況下只與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討論的任何跡象。

52

這一年之後碰碰...

這是和主要的瀏覽器仍然不同:

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); 

gisttest in current browser

的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,歌劇12,節點0.6,火狐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]