我想迭代一些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的结果是数组吗?如果不是,是什么?
如前所述,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';
}
);
编辑:尽管在新版本的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。
你可以使用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的集合,但其他方法如map或filter都没有,所以这个语法仍然有用:
[...document.querySelectorAll(".myclass")].map(
(element, index, array) => {
// do stuff
}
);
[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);