“for (... in ...)”循环中的元素顺序
-
07-07-2019 - |
题
Javascript 中的“for…in”循环是否按照声明的顺序循环遍历哈希表/元素?有没有不按顺序执行的浏览器?
我希望使用的对象将被声明 一次 并且永远不会被修改。
假设我有:
var myObject = { A: "Hello", B: "World" };
我进一步将它们用于:
for (var item in myObject) alert(item + " : " + myObject[item]);
我可以期待 'A :“Hello”总是出现在“B”之前:最体面的浏览器中的“世界”?
解决方案
目前,所有主要浏览器都按照定义的顺序循环对象的属性。除了少数情况外,Chrome 也可以这样做。...]这种行为明确地被Ecmasiprcript规范不确定。在 ECMA-262,第 12.6.4 节中:
枚举属性的机制...取决于实现。
然而,规范与实现有很大不同。所有现代化的授权实现通过对象属性按照它们定义的顺序进行。因此,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、火狐 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、节点 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]
来自 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 实现都将按声明顺序枚举。
删除属性时迭代顺序也很混乱,但在本例中仅适用于 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。
这并没有回答问题本身,而是提供了基本问题的解决方案。
假设您不能依赖顺序来保存,为什么不使用以键和值作为属性的对象数组呢?
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
见笔 for (...in...) 按顺序寻址 通过 JDQ (@JDQ) 在 代码笔.