使用Array.forEach迭代getElementsByClassName的结果

我想迭代一些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的结果是数组吗?如果不是,是什么?

332620 次浏览

它不返回Array,而是返回节点列表

getElementsByClassName的结果是数组吗?

没有

如果不是,是什么?

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

不,它不是数组。作为在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);
});

编辑:尽管在新版本的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。

如前所述,getElementsByClassName返回< em > HTMLCollection < / em >,其定义为

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

以前,一些浏览器会返回< em > < / em >节点列表

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

区别很重要,因为DOM4现在将节点列表s定义为可迭代对象。

根据Web IDL草案,

实现声明为可迭代的接口的对象

.

.

.

请注意: ECMAScript语言绑定中的接口 iterable将有“entries”,“forEach”,“keys”,“values”和 @@iterator属性在它的接口原型对象

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

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

注意,这还没有得到广泛支持。也可参见对于Node.childNodes?

你可以使用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
}
);

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


虽然替代函数querySelectorAll(这有点让getElementsByClassName过时了)返回一个原生有forEach的集合,但其他方法如mapfilter都没有,所以这个语法仍然有用:

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


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

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

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

现代浏览器(包括Edge,不包括IE)支持:
我可以使用querySelectorAll吗 < br > NodeList.prototype.forEach () < / p >

中数: Document.querySelectorAll ()

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

在ES2015中,转换类数组对象用于Array.prototype.forEach()的一个简单方法是使用展开操作符或传播的语法:

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


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

这是更安全的方法:

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

getElementsByClassName在现代浏览器中返回HTMLCollection

< p > 类似数组的对象,类似于arguments,可由for...of循环迭代,参见下面中数 doc对它的描述:

< p > 为…语句创建一个遍历可迭代对象的循环, 包括:内置字符串,数组,类数组对象(例如,参数 或NodeList), TypedArray, Map, Set和用户定义的迭代对象。它 类要执行的语句调用自定义迭代钩子 对象的每个不同属性的值

Javascript的例子

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

打印稿的例子

let elements = document.getElementsByClassName('classname');
let i;


for (i = 0; i < elements.length; i++) {


if (elements[i] instanceof HTMLElement) {
elements[i].style.display = "none";
}


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

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';
}
);

使用这段代码将forEach方法添加到HTMLCollection中

/**
*
* @type {Function}
*/
HTMLCollection.prototype.forEach = HTMLCollection.prototype.forEach ||
function (callBack) {
for (let i = 0; i < this.length; i++) {
callBack(this[i])
}
};

然后你的代码将工作:

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

最简单的解决方案:

Object.assign (HTMLCollection。prototype, {forEach(事件){Array.prototype.forEach。调用(this, (element) =>事件(元素));}});


之后你可以这样写:

document.getElementsByClassName(“disable") .forEach((元素)=比;alert (element.classList [0]));


🙂

for typescript,我更喜欢迭代

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