我想迭代一些DOM元素,我这样做:

document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
  //do stuff
});

但是我得到了一个错误:

document.getElementsByClassName(“myclass”)。forEach不是一个函数

我使用Firefox 3,所以我知道getElementsByClassName和Array。每个人都在场。这很好:

[2, 5, 9].forEach( function(element, index, array) {
  //do stuff
});

getElementsByClassName的结果是数组吗?如果不是,是什么?


当前回答

for typescript,我更喜欢迭代

for(let element of Array.from(document.querySelectorAll('.myclass'))){
   //my code
}

其他回答

编辑:尽管在新版本的HTML中返回类型发生了变化(参见Tim Down的更新答案),但下面的代码仍然可以工作。

正如其他人所说,它是一个NodeList。这里有一个完整的工作示例,你可以尝试一下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <script>
            function findTheOddOnes()
            {
                var theOddOnes = document.getElementsByClassName("odd");
                for(var i=0; i<theOddOnes.length; i++)
                {
                    alert(theOddOnes[i].innerHTML);
                }
            }
        </script>
    </head>
    <body>
        <h1>getElementsByClassName Test</h1>
        <p class="odd">This is an odd para.</p>
        <p>This is an even para.</p>
        <p class="odd">This one is also odd.</p>
        <p>This one is not odd.</p>
        <form>
            <input type="button" value="Find the odd ones..." onclick="findTheOddOnes()">
        </form>
    </body>
</html>

这适用于IE 9, FF 5, Safari 5和Win 7上的Chrome 12。

不,它不是数组。正如DOM4中指定的那样,它是一个HTMLCollection(至少在现代浏览器中是这样)。旧的浏览器返回一个NodeList)。

在所有现代浏览器(几乎所有其他IE <= 8)中,你可以调用Array的forEach方法,将元素列表(无论是HTMLCollection还是NodeList)作为this值传递给它:

var els = document.getElementsByClassName("myclass");

Array.prototype.forEach.call(els, function(el) {
    // Do stuff here
    console.log(el.tagName);
});

// Or
[].forEach.call(els, function (el) {...});

如果你很高兴能够使用ES6(即你可以安全地忽略ie或你正在使用ES5转译器),你可以使用Array.from:

Array.from(els).forEach((el) => {
    // Do stuff here
    console.log(el.tagName);
});

getElementsByClassName的结果是数组吗?

No

如果不是,是什么?

与所有返回多个元素的DOM方法一样,它是一个NodeList,参见https://developer.mozilla.org/en/DOM/document.getElementsByClassName

如前所述,getElementsByClassName返回一个HTMLCollection,它被定义为

[Exposed=Window]
interface HTMLCollection {
  readonly attribute unsigned long length;
  getter Element? item(unsigned long index);
  getter Element? namedItem(DOMString name);
};

以前,一些浏览器会返回一个NodeList。

[Exposed=Window]
interface NodeList {
  getter Node? item(unsigned long index);
  readonly attribute unsigned long length;
  iterable<Node>;
};

区别很重要,因为DOM4现在将nodelist定义为可迭代对象。

根据Web IDL草案,

实现声明为可迭代的接口的对象 支持迭代以获得值序列。 注意:在ECMAScript语言绑定中,接口为 iterable将有“entries”,“forEach”,“keys”,“values”和 接口原型对象上的@@iterator属性。

这意味着,如果你想使用forEach,你可以使用一个返回节点列表的DOM方法,比如querySelectorAll。

document.querySelectorAll(".myclass").forEach(function(element, index, array) {
  // do stuff
});

注意,这还没有得到广泛支持。另见Node.childNodes?

下面是我在jsperf上创建的一个测试: https://jsperf.com/vanillajs-loop-through-elements-of-class

Chrome和Firefox中性能最好的版本是旧的for循环结合document.getElementsByClassName:

var elements = document.getElementsByClassName('testClass'), elLength = elements.length;
for (var i = 0; i < elLength; i++) {
    elements.item(i).textContent = 'Tested';
};

在Safari中,这个变体是赢家:

var elements = document.querySelectorAll('.testClass');
elements.forEach((element) => {
    element.textContent = 'Tested';
});

如果你想要所有浏览器的性能最好的变体,它可能是这个:

var elements = document.getElementsByClassName('testClass');
Array.from(elements).map(
    (element) => {
        return element.textContent = 'Tested';
    }
);