15

我在 Javascript 中遇到了一个奇怪的行为。我明白了

“对象不支持此属性或方法”

removeAttribute以下代码中的函数异常:

var buttons = controlDiv.getElementsByTagName("button");
for ( var button in buttons )
    button.removeAttribute('disabled');

当我用以下代码更改代码时,问题就消失了:

var buttons = controlDiv.getElementsByTagName("button");
for ( var i = 0; i < buttons.length; i++ )
    buttons[i].removeAttribute('disabled');

button里面的值是for...in多少?

4

4 回答 4

48

不要for..in用于数组迭代。

重要的是要理解 Javascript Array[]用于访问索引的方括号语法 ( ) 实际上是从Object...

obj.prop === obj['prop']  // true

for..in结构不像for..each/in其他语言(php、python 等)中更传统的那样工作。

Javascriptfor..in旨在迭代对象的属性。生成每个属性的密钥。将此Object's 括号语法结合使用,您可以轻松访问所需的值。

var obj = {
    foo: "bar",
    fizz: "buzz",
    moo: "muck"
};

for ( var prop in obj ) {
    console.log(prop);      // foo / fizz / moo
    console.log(obj[prop]); // bar / buzz / muck
}

并且因为数组只是一个具有顺序数字属性名称(索引)的对象,所以for..in以类似的方式工作,产生数字索引就像它产生上面的属性名称一样。

该结构的一个重要特征for..in是它继续搜索原型链上的可枚举属性。它还将迭代继承的可枚举属性。由您来验证当前属性是否直接存在于本地对象上,而不是它附加到的原型上hasOwnProperty()...

for ( var prop in obj ) {
    if ( obj.hasOwnProperty(prop) ) {
        // prop is actually obj's property (not inherited)
    }
}

更多关于原型继承

在 Array 类型上使用for..in结构的问题在于,对于属性的生成顺序没有任何保证......一般来说,这是处理数组的一个非常重要的特性。

另一个问题是它通常标准for实现慢。

底线

使用 afor...in来迭代数组就像使用螺丝刀的枪托来驱动钉子...为什么不直接使用锤子 ( for)?

于 2011-03-10T18:11:18.870 回答
7

for...in当你想循环一个对象的属性时使用。但它与普通循环的工作方式相同for:循环变量包含当前的“索引”,表示对象的属性而不是值。

要遍历数组,您应该使用普通for循环。buttons不是一个数组,而是一个NodeList(类似数组的结构)。

buttons如果使用with迭代for...in

for(var i in a) {
    console.log(i)
}

您将看到它输出如下内容:

1
2
...
length
item

因为lengthitem是类型对象的两个属性NodeList。因此,如果您天真地使用for..in,您会尝试访问buttons['length'].removeAttribute()将引发错误buttons['length']的函数,而不是 DOM 元素。

所以正确的方法是使用正常的for循环。但是还有一个问题:

NodeLists 是实时的,这意味着每当您访问 eglength时,列表都会更新(再次搜索元素)。因此,您应该避免对length.

例子:

for(var i = 0, l = buttons.length; i < l, i++)
于 2011-03-10T18:17:29.323 回答
0

for(var key in obj) { }遍历对象中的所有元素,包括其原型的元素。因此,如果您正在使用它并且不知道任何扩展Object.prototype,您应该始终测试obj.hasOwnProperty(key)并在此检查返回 false 时跳过密钥。

for(start; continuation; loop)是一个 C 风格的循环:start在循环之前执行,continuation经过测试,循环只有在它为真时才继续,loop在每个循环之后执行。

于 2011-03-10T18:13:44.230 回答
0

虽然 for..in 通常不应该用于数组,但是在 ES5 之前,有一个案例可以将它与稀疏数组一起使用。

如其他答案所述,for..in 和 Arrays 的主要问题是:

  1. 属性不一定按顺序返回(即不是 0、1、2 等)
  2. 返回所有可枚举的属性,包括非索引属性和[[Prototype]]链上的属性。这会导致性能降低,因为可能需要进行hasOwnProperty测试以避免继承属性。

在 ES5 之前使用 for..in 的一个原因是为了提高稀疏数组的性能,前提是顺序无关紧要。例如,在下面:

var a = [0];
a[1000] = 1;

迭代using for..in 将比使用 for 循环快得多,因为它只会访问两个属性,而 for 循环将尝试 1001

但是,ES5 的forEach使这种情况变得多余,它只访问存在的成员,所以:

a.forEach();

也只会按顺序迭代两个属性。

于 2014-10-08T05:08:51.477 回答