Javascript中的"for ... in"循环是否按照声明的顺序循环遍历hashtables/elements?是否有一个浏览器没有按顺序执行?
我想要使用的对象将被声明一次,永远不会被修改.
假设我有:
var myObject = { A: "Hello", B: "World" };
我进一步使用它们:
for (var item in myObject) alert(item + " : " + myObject[item]);
在大多数体面的浏览器中,我可以期待'A:'你好''总是先来'B:'世界"吗?
引用John Resig:
目前,所有主流浏览器都按照定义它们的顺序循环对象的属性.除了几个案例外,Chrome也可以做到这一点.[...] ECMAScript规范明确未明确定义此行为.在ECMA-262第12.6.4节中:
枚举属性的机制......依赖于实现.
但是,规范与实现完全不同.ECMAScript的所有现代实现都按照定义它们的顺序迭代对象属性.因此,Chrome团队认为这是一个错误,并将修复它.
所有浏览器都遵循定义顺序,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"
这方面的技术性不如在任何时候可能发生变化的事实重要.不要依赖这样的事情.
简而言之:如果订单对您很重要,请使用数组.
一年之后就把这个搞得一团糟......
它是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]
从ECMAScript语言规范,第12.6.4节(在for .. in
循环中):
枚举属性的机制取决于实现.枚举的顺序由对象定义.
第4.3.3节("对象"的定义):
它是一个无序的属性集合,每个属性都包含一个原始值,对象或函数.存储在对象属性中的函数称为方法.
我想这意味着你不能依赖于JavaScript实现中以一致顺序枚举的属性.(依靠语言的特定于实现的细节,无论如何都是糟糕的风格.)
如果您希望定义订单,则需要实现定义它的内容,例如在使用它访问对象之前排序的键数组.
for/in枚举的对象元素是未设置DontEnum标志的属性.ECMAScript,又名Javascript,标准明确地说"一个对象是一个无序的属性集合"(参见http://www.mozilla.org/js/language/E262-3.pdf第8.6节).
假设所有Javascript实现都将按声明顺序枚举,这将不符合标准(即安全).