元素顺序在“for(… in …)”循环中
Javascript中的“for … in”循环是否按照声明的顺序通过hashtables / elements? 有一个浏览器不按顺序吗?
我希望使用的对象将被声明一次 ,永远不会被修改。
假设我有:
var myObject = { A: "Hello", B: "World" };
我进一步使用它们:
for (var item in myObject) alert(item + " : " + myObject[item]);
我可以期待'A:'你好''在最合适的浏览器中总是出现在'B:'World''之前吗?
引用John Resig :
目前,所有主stream浏览器都按照定义的顺序遍历对象的属性。 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年 ,主stream浏览器还是有所不同:
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实现中以一致的顺序枚举的属性。 (无论如何,依靠某个语言的特定实现细节,这将是一种糟糕的风格。)
如果你想定义你的订单,你将需要实现一些定义它的东西,比如你在访问对象之前要对其进行sorting的一组键。
枚举对象的元素是没有设置DontEnum标志的属性。 ECMAScript(又名Javascript)标准明确指出:“一个对象是一个无序的属性集合”(见http://www.mozilla.org/js/language/E262-3.pdf第8.6节)。;
假设所有Javascript实现都将按照声明顺序进行枚举,这不会是符合标准(即安全)的标准。
迭代次序也与删除属性相混淆,但是在这种情况下只用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上的讨论有任何迹象,那么修改规范以修正迭代顺序的愿望似乎是相当普遍的开发人员的愿望。;
在IE6中,顺序是不能保证的。
订单不能被信任。 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.