我想遍历一些DOM元素,我正在这样做:

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


,但是我得到一个错误:


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


我正在使用Firefox 3,因此我知道getElementsByClassNameArray.forEach都存在。可以正常工作:

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


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

#1 楼

不需要。按照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(即您可以放心地忽略Internet Explorer或使用ES5编译器),则可以使用Array.from

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


评论


无需先将其转换为数组。只需使用[] .forEach.call(elsArray,function(){...})。

–凯
2013年4月9日19:13



它不是NodeList。这是一个类似数组的对象。我什至不认为它具有实例类型。 querySelectorAll方法虽然返回一个NodeList。

– Maksim Vi。
15年1月21日在22:06

@MaksimVi。您是完全正确的:DOM4指定document.getElementsByClassName()应该返回HTMLCollection(这非常相似,但不是NodeList)。感谢您指出错误。

– Tim Down
15年1月21日在23:14

@MaksimVi .:我想知道这是否在某个时候改变了。我通常检查这些东西。

– Tim Down
15年1月21日在23:16

@TimDown,感谢HTMLCollection技巧。现在我终于可以使用HTMLCollection.prototype.forEach = Array.prototype.forEach;在我的代码中。

– Maksim Vi。
2015年1月21日在23:31



#2 楼

您可以使用Array.from将集合转换为数组,这比Array.prototype.forEach.call更干净:

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


在不支持Array.from的旧版浏览器中,您需要使用类似Babel。


ES6还添加了以下语法:

[...document.getElementsByClassName("myclass")].forEach(
    (element, index, array) => {
        // do stuff
    }
);


使用...进行的销毁销毁适用于所有类似数组的对象,而不适用于仅数组本身,然后使用良好的旧数组语法从值构造数组。


替代函数querySelectorAll(有点使getElementsByClassName过时)返回确实包含forEach的集合本机地,缺少mapfilter之类的其他方法,因此此语法仍然有用:

[...document.querySelectorAll(".myclass")].map(
    (element, index, array) => {
        // do stuff
    }
);

[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);


评论


注意:如未建议进行转码(Babel),则在IE
– Sean
16-09-5在5:53



#3 楼

或者您可以使用querySelectorAll返回NodeList:

document.querySelectorAll('.myclass').forEach(...)


现代浏览器(包括Edge,但不包括IE)支持:我可以使用querySelectorAllNodeList.prototype.forEach()

MDN:Document.querySelectorAll()

评论


注意getElementByClassName的性能损失

– SzabolcsPáll
18年8月30日在14:20

与其他更密集的任务(如修改DOM)相比,性能损失可忽略不计。如果我在1毫秒内执行其中的60,000个,那么我很确定这对于任何合理的使用都不会成为问题:)

–icl7126
19年7月31日在13:13



您链接了错误的基准。这是正确的一种度量,即.net / Benchmarks / Show / 4076/0 /…只需在我的低端手机上运行它,就可以得到160k / s与380k / s的对比。既然您提到了DOM操作,这也是measurethat.net/Benchmarks/Show/5705/0/…的结果:50k / s与130k / s。如您所见,操纵DOM的速度甚至更慢,这可能是由于NodeList是静态的(如其他人所提到的)。在大多数使用情况下仍然可以忽略不计,但是速度却慢了将近3倍。

– SzabolcsPáll
19年8月1日在6:43

IE也不支持NodeList的forEach方法。但是有一种解决方法,例如使用传播运算符或Array.from

–梅尔基亚
10月13日9:54

#4 楼

编辑:尽管返回类型在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>


此版本可在Win 7上的IE 9,FF 5,Safari 5和Chrome 12中使用。

评论


2020年12月验证该代码仍然有效。

–james.garriss
12月1日13:16

#5 楼

getElementsByClassName()的结果不是数组,而是类似数组的对象。具体来说,它称为HTMLCollection,不要与NodeList(具有自己的forEach()方法)相混淆。

ES2015的一种简单方法是将类似数组的对象转换为可用于Array.prototype.forEach()提到的是使用扩展运算符或扩展语法:

const elementsArray = document.getElementsByClassName('myclass');

[...elementsArray].forEach((element, index, array) => {
    // do something
});


评论


我觉得这确实是在现代浏览器中执行此操作的正确方法。这是创建要解决的确切用例扩展语法。

–马特·科罗斯托夫(Matt Korostoff)
17年5月5日在16:10

#6 楼


getElementsByClassName的结果是否为数组?





如果不是,那是什么?

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

#7 楼

如前所述,getElementsByClassName返回一个HTMLCollection,它定义为/>
区别很重要,因为DOM4现在将NodeLists定义为可迭代的。

根据Web IDL草案,


实现接口的对象声明为可迭代
支持迭代以获取值序列。


注意:在ECMAScript语言绑定中,
可迭代的接口将在其接口原型对象上具有“条目”,“ forEach”,“键”,“值”和
@@ iterator属性。



,如果要使用forEach,则可以使用DOM方法,该方法返回一个NodeList,例如querySelectorAll

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


请注意,此方法尚未得到广泛支持。另请参阅Node.childNodes的forEach方法?

评论


Chrome 49返回forEach而不起作用

– Vitaly Zdanevich
16年4月23日在15:31

@VitalyZdanevich试试Chromium 50

– Oriol
16年4月23日在15:36

在Chrome 50上,我正在获取document.querySelectorAll(...)。forEach不是一个函数

– Vitaly Zdanevich
16年6月2日在10:42

@VitalyZdanevich它可以在Chromium 50上运行,但仍然可以在Chromium 53上运行。也许它不够稳定,无法运送到Chrome 50。

– Oriol
16年6月2日在17:43

#8 楼

getElementsByClassName在现代浏览器中返回HTMLCollection。
是类似于数组的对象,类似于参数,可以通过for...of循环对其进行迭代,请参见下面的MDN文档所说的内容:

... of语句创建一个循环遍历可迭代对象,
包括:内置String,Array,类似Array的对象(例如arguments
或NodeList),TypedArray,Map,Set和user定义的可迭代项。它
调用带有要针对对象的每个不同属性的值执行的语句的自定义迭代挂钩。

示例
for (const element of document.getElementsByClassName("classname")){
   element.style.display="none";
}


评论


并非如此,根据Typescript:错误TS2488:类型'HTMLCollectionOf '必须具有返回迭代器的'[Symbol.iterator]()'方法。

–乌龟很可爱
1月1日7:37

@TurtlesAreCute,这里OP使用的是JavaScript而不是打字稿,我已经按照香草js的建议进行了回答,因此在打字稿中,它可以是该问题的不同解决方案。

– Haritsinh Gohil
1月1日7:46



@TurtlesAreCute,顺便说一句,它也可以在打字稿中使用,但是您必须提到包含特定css类元素的变量的正确类型,因此可以对其进行相应的转换,有关详细信息,请参见此答案。

– Haritsinh Gohil
1月1日8:12

这很容易是最好的答案,并且在Typescript中效果很好。

– Timmmm
10月23日19:57

#9 楼

它不返回Array,它返回NodeList。

#10 楼

这是更安全的方法:

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);


#11 楼

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

Chrome和Firefox中性能最高的版本是与document.getElementsByClassName结合使用的好for循环: br />如果您想为所有浏览器使用最完美的版本,可能就是这样:

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