337

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

4

11 回答 11

528

不。正如DOM4 中指定的那样,它是一个HTMLCollection(至少在现代浏览器中。旧浏览器返回 a 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);
});
于 2010-10-06T10:36:11.987 回答
115

您可以使用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);
于 2016-06-21T10:22:38.993 回答
44

或者您可以使用querySelectorAllwhich 返回NodeList

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

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

MDN: Document.querySelectorAll()

于 2017-05-13T08:10:20.330 回答
15

编辑:虽然返回类型在新版本的 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。

于 2011-06-29T15:51:06.963 回答
12

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

使用 ES2015 转换类似数组的对象以用于Array.prototype.forEach()尚未提及的一种简单方法是使用扩展运算符或扩展语法

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

[...elementsArray].forEach((element, index, array) => {
    // do something
});
于 2017-10-03T00:00:15.827 回答
11

getElementsByClassName在现代浏览器中返回HTMLCollection 。

它是 类似数组的对象,类似于可循环迭代的参数,for...of请参阅下面的MDN文档所说的:

for...of 语句创建一个循环遍历可迭代对象,包括:内置字符串、数组、类数组对象(例如,参数 或 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";
  }

}
于 2019-07-03T06:52:23.927 回答
4

getElementsByClassName 的结果是一个数组吗?

如果不是,那是什么?

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

于 2010-10-06T10:31:03.370 回答
3

如前所述,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 语言绑定中,可迭代的接口将 在其接口原型对象上具有“entries”、“forEach”、“keys”、“values”和@@iterator属性。

这意味着,如果您想使用forEach,可以使用返回NodeList的 DOM 方法,例如querySelectorAll.

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

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

于 2016-04-23T09:30:28.610 回答
2

这是更安全的方法:

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);
于 2019-06-22T09:51:52.653 回答
1

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

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

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';
    }
);
于 2019-09-10T13:07:43.607 回答
0

它不返回一个Array,它返回一个NodeList

于 2010-10-06T10:30:56.247 回答