为什么 for...in 循环会遍历函数名?

6

在IE8中测试一些JavaScript代码时,我在执行简单的for..in循环时遇到了一些奇怪的行为:

var categories = ['for', 'bar', 'steam'];
for(var key in categories) {
    console.log(key);
}

输出:

0
1
2
forEach
map
filter
reduce
indexOf
end

这包括数组原型函数,对吧?这绝不是它应该工作的方式。为什么会这样呢?

顺便说一下,当将循环更改为for (var key=0; key < categories.length, key++)时,它当然可以工作。


4
for...in 符号用于遍历对象的属性。请参考 MDN 上的第二个警告:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for...in。 - Blender
谢谢大家的快速回答和解决问题! - quape
3个回答

2

for..in 适用于对象,而不是数组。请使用常规的 for 循环:

for (var i = 0; i < categories.length; i++) {
  console.log(categories[i]);
}

for...in循环适用于数组,当您不关心索引时,但这并不建议。您遇到的问题是因为for...in查找对象的所有属性,包括原型中的属性,因此建议始终检查属性是否实际存在于对象中。

for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
        // do something
    }
}

如果您不想查看继承的属性,建议不要这样做,但有时候您需要查看。 - Ruan Mendes

2
这是因为你可能正在使用一个扩展Array.prototype的库。它在其他浏览器中不会发生的原因是它们已经本地支持这些方法。由于IE不支持它,所以有一些代码在JS中添加它,这使得这些方法可枚举。
这是你不应该使用for in与数组的原因之一。
另一个原因是for in不能保证迭代顺序,虽然它在大多数浏览器中可以工作,但它在规范中明确留下了未定义行为。John Resig自己针对chrome提出了一个bughttp://code.google.com/p/chromium/issues/detail?id=883,但它被关闭了,因为没有要求属性需要排序。
坚持使用标准循环。

你说的“虽然它不起作用”是什么意思?它确实可以工作,但是它按照你所描述的方式无序地枚举属性。此外,我认为没有什么东西可以“使方法可枚举”,你添加到数组中的所有方法默认都是可枚举的。 - Nappy
@Nappy,我不知道你在说什么。我说在大多数浏览器中,它是可以工作的(按正确顺序迭代)。如果您自己添加属性,则它们将是可枚举的,但本机方法不可枚举。 - Ruan Mendes
啊,抱歉这是语言问题,你真正的意思是“这是在大多数浏览器中的工作方式”,你使用的“though”让我感到困惑 :) - Nappy
@Nappy,你使用的某个东西让我感到困惑了...我们在SO这里不使用即时通讯语言。我仍然无法确定你的观点是什么,难道你不能理解“它确实有效”是指按正确顺序迭代数组吗? - Ruan Mendes

0

看起来你正在使用一些框架。 遍历数组的方法不好,因为有些框架会向标准原型中添加功能。

 for (var i=0, len=arr.length; i<len; ++i) {

 }

那段代码在任何地方都能运行。


for..in 是自 JS 1 版本以来就是 JavaScript 规范的一部分(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for...in)。 - just.another.programmer
我知道。但是,只有在您可以保证没有人更改Array.prototype的情况下,才可以使用“for in”数组迭代。我认为这不安全。 - Damask

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接