为什么JavaScript的For … In循环不推荐用于数组?

Why is JavaScript's For…In loop not recommended for arrays?

本问题已经有最佳答案,请猛点这里访问。

我在某个地方读到(抱歉,我找不到链接),不建议数组使用for…in循环。这里说:http://www.openjs.com/articles/for ou loop.php它是用于关联数组的,在http://www.w3schools.com/js/js ou loop ou for ou in.asp中它是用于迭代对象的所有属性(它没有说它可以用于数组)。我不知道该相信谁。我不想把这个问题变成辩论。我只是想知道我是否可以在代码中使用它,而不会产生不可预见的副作用。谢谢!


数组是一个对象,数组元素只是将数字索引转换为字符串的属性。例如,arr[123]引用数组对象arr中的属性"123"。

for ... in构造适用于所有对象,而不仅仅是数组,这会导致混淆。

当有人使用一个数组时,程序员通常只打算迭代所有元素,甚至最有可能是按顺序迭代。例如,如果数组包含一组数字,那么程序员很可能打算迭代一个数字流。语义与其他编程语言中的数组迭代非常相似,因此很容易混淆。

在JavaScript中,此构造不会按顺序迭代数组元素。它迭代数组的所有属性名(包括继承的原型函数的名称、添加到它的任何属性、添加到它的任何其他非元素属性等),并且完全不按顺序进行。在早期的浏览器中,它甚至可以找到length属性,尽管在最近的浏览器中,这些属性现在被定义为隐藏的,正是因为这个原因——人们一直在使用它!

使用上面的整数数组,您得到的不是数字流,而是文本字符串流。而不是元素值,而是属性的名称(只是数字索引,而不是任何顺序)。如果程序员来自另一种编程语言,这很可能不是程序员的意思。如果存储在数组中的元素恰好是相似的数值,它会把所有人都搞糊涂。

所以你不应该这样做。你不应该使用一个看起来很明显的语言结构,但实际上它会做一些完全不同的事情。它会产生非常模糊和很难找到的错误。


在prototype.js库文档中给出了几个很好的理由:http://www.prototypejs.org/api/array

基本上,使用for…in迭代数组是很脆弱的,因为任何其他代码都可以向数组原型添加属性,然后这些属性将成为每个数组对象的可枚举属性。


我已经在几个浏览器(火狐3、Opera 9、IE6、IE9测试版、Chrome)中测试了数组迭代,它工作得很好;我似乎还记得一些跨浏览器的不兼容性,但我一定搞错了。

不过,还有一个警告:

如前所述,for ... in语法用于迭代对象的属性;因此,对于数组,该数组对象的所有属性也将与元素一起迭代。通常,数组对象只有与其中的键对应的属性,但是如果另一个脚本修改了Array.prototype(例如某些框架),那么添加的方法/属性也会意外地出现在迭代中。


使用for(... in ...)迭代数组不会得到数字键,而是得到字符串值。

它将在原型上为您定义属性,因此如果任何代码扩展Array,例如通过执行以下操作:

1
Array.prototype.each = ...;

然后您将看到each房地产。

没有Gaurantee可以按数组索引顺序获取属性。例如,尝试迭代

1
2
3
var arr = []
arr[1] = 1;
arr[0] = 0;

在很多浏览器中,你会在0之前得到1

你不一定能得到所有的指数。尝试重复

1
[0,,,3]

您将无法获得索引12