Javascript中的“for…in”循环是否按照声明的顺序遍历哈希表/元素?有没有浏览器是不按顺序执行的? 我希望使用的对象只声明一次,永远不会被修改。

假设我有:

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

我进一步将它们用于:

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

在大多数像样的浏览器中,“A:“Hello”总是出现在“B:“World”之前吗?


当前回答

引用John Resig的话:

Currently all major browsers loop over the properties of an object in the order in which they were defined. Chrome does this as well, except for a couple cases. [...] This behavior is explicitly left undefined by the ECMAScript specification. In ECMA-262, section 12.6.4: The mechanics of enumerating the properties ... is implementation dependent. However, specification is quite different from implementation. All modern implementations of ECMAScript iterate through object properties in the order in which they were defined. Because of this the Chrome team has deemed this to be a bug and will be fixing it.

所有浏览器都尊重定义顺序,除了Chrome和Opera,它们对每个非数字属性名都遵守定义顺序。在这两个浏览器中,属性被按顺序拉到第一个非数值属性之前(这与它们如何实现数组有关)。Object的顺序是一样的。还有钥匙。

这个例子应该清楚地说明发生了什么:

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"

这方面的技术细节并不重要,重要的是这一点随时都可能改变。不要指望事情会一直这样下去。

简而言之:如果顺序对你很重要,就使用数组。

其他回答

在IE6中,不保证顺序。

引用John Resig的话:

Currently all major browsers loop over the properties of an object in the order in which they were defined. Chrome does this as well, except for a couple cases. [...] This behavior is explicitly left undefined by the ECMAScript specification. In ECMA-262, section 12.6.4: The mechanics of enumerating the properties ... is implementation dependent. However, specification is quite different from implementation. All modern implementations of ECMAScript iterate through object properties in the order in which they were defined. Because of this the Chrome team has deemed this to be a bug and will be fixing it.

所有浏览器都尊重定义顺序,除了Chrome和Opera,它们对每个非数字属性名都遵守定义顺序。在这两个浏览器中,属性被按顺序拉到第一个非数值属性之前(这与它们如何实现数组有关)。Object的顺序是一样的。还有钥匙。

这个例子应该清楚地说明发生了什么:

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"

这方面的技术细节并不重要,重要的是这一点随时都可能改变。不要指望事情会一直这样下去。

简而言之:如果顺序对你很重要,就使用数组。

一年后再碰这个……

现在已经是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);

Gist或测试在当前浏览器

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] 

这并没有回答问题本身,但为基本问题提供了一个解决方案。

假设您不能依赖顺序来保存,为什么不使用具有键和值的对象数组作为属性呢?

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

现在,由您来确保键是唯一的(假设这对您也很重要)。同样,直接寻址也发生了变化,for(…in…)现在将索引作为“键”返回。

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1
See the Pen

为(…in…)编址

by JDQ (

@JDQ

) on

CodePen

.

迭代顺序也与删除属性有关,但在这种情况下仅针对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上的讨论有任何指示的话,那么改变规范以修正迭代顺序的愿望似乎是开发人员中相当流行的愿望。