2008-11-11 209 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]