JS:使用 Array.forEach 迭代 getElementsByClassName 的结果

IT技术 javascript foreach getelementsbyclassname
2021-01-16 20:39:20

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

6个回答

不。正如在 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);
});
它不是一个 NodeList。它是一个类似数组的对象。我什至认为它没有实例类型。querySelectorAll方法虽然返回一个 NodeList。
2021-03-11 20:39:20
@MaksimVi。:我想知道这是否在某个时候发生了变化。我通常会检查这些东西。
2021-03-14 20:39:20
@TimDown,感谢您的HTMLCollection提示。现在我终于可以HTMLCollection.prototype.forEach = Array.prototype.forEach;在我的代码中使用了。
2021-03-23 20:39:20
无需先将其转换为数组。只需使用[].forEach.call(elsArray, function () {...}).
2021-03-25 20:39:20
@马克西姆维。你说得对:DOM4 指定document.getElementsByClassName()应该返回一个HTMLCollection(非常相似,但不是 NodeList)。感谢您指出错误。
2021-04-01 20:39:20

您可以使用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);
注意:没有按照建议(Babel)进行转译,这在 IE < Edge、Opera、Safari < 9、Android 浏览器、Android 版 Chrome 等中不兼容)来源:mozilla dev docs
2021-03-26 20:39:20

或者您可以使用querySelectorAllwhich 返回NodeList

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

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

MDN: Document.querySelectorAll()

IE 也不支持 NodeList 的 forEach 方法。但是有一种解决方法,例如使用扩展运算符或 Array.from
2021-03-14 20:39:20
请记住 getElementByClassName 的性能损失
2021-03-15 20:39:20
您链接了错误的基准。这是正确的一个measurethat.net/Benchmarks/Show/4076/0/……在我的低端手机上运行它,得到160k/s vs 380k/s。既然你提到了 DOM 操作,那么这里也是measurethat.net/Benchmarks/Show/5705/0 / ... Got 50k/s vs 130k/s。如您所见,操作 DOM 甚至更慢,这可能是因为 NodeList 是静态的(正如其他人所提到的)。在大多数用例中仍然可以忽略不计,但仍然慢了近 3 倍。
2021-03-21 20:39:20
与修改 DOM 等其他更密集的任务相比,性能损失可以忽略不计如果我在 1 毫秒内执行60,000 个这些,我很确定它不会成为任何合理使用的问题:)
2021-03-24 20:39:20

编辑:尽管新版本的 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 月验证此代码仍然有效。
2021-03-14 20:39:20

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

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

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

[...elementsArray].forEach((element, index, array) => {
    // do something
});
我觉得这真的是在现代浏览器中做到这一点的正确方法。这是创建用于解决的确切用例传播语法。
2021-03-12 20:39:20