在getElementsByClassName的数组上使用forEach会导致“ TypeError:未定义不是函数”


91

我的JSFiddle中,我只是尝试遍历一系列元素。日志语句证明,该数组为非空。但是,forEach给我的电话给了我(不是那么有用)“未捕获TypeErrorundefined不是函数”错误。

我一定在做些愚蠢的事。我究竟做错了什么?

我的代码:

var arr = document.getElementsByClassName('myClass');
console.log(arr);
console.log(arr[0]);
arr.forEach(function(v, i, a) {
  console.log(v);
});
.myClass {
  background-color: #FF0000;
}
<div class="myClass">Hello</div>


8
arr不是数组,而是一个HTMLCollection。它没有与数组相同的方法。developer.mozilla.org/zh-CN/docs/Web/API/…。这甚至是关于它的SO帖子:stackoverflow.com/questions/13433799/…–
Ian

有点[1,2,3].forEach(function(v,i,a) { console.log(v); });好。在我的示例中,此数组与数组有什么区别?
2014年

不要有一个数组在你的榜样。是什么使您认为它是数组?
伊恩

3
@Jer:arr instanceof Array将导致false无法使用Array对象的任何原型方法,例如Array.prototype.forEach()arr是一个HTMLCollection和一个类似object的数组(但不继承自或实例化Array)。因此,您的标准for循环将可以正常工作,因为它仅循环访问对象的索引,而不是的原型Array
2014年

1
@Jer-您应该研究内置对象和宿主对象之间的区别。前者符合ECMA-262,后者仅符合主人的意愿。DOM具有许多对象,这些对象允许通过索引访问成员(document.images,document.forms,form.elements,select.options等),这些对象主要基于NodeList接口
RobG 2014年

Answers:


162

那是因为 document.getElementsByClassName返回HTMLCollection,而不是数组。

幸运的是,它是一个“类似数组”的对象(这说明了为什么将其记录为好像是一个对象以及为什么可以使用标准for循环进行迭代),因此可以执行以下操作:

[].forEach.call(document.getElementsByClassName('myClass'), function(v,i,a) {

借助ES6(在现代浏览器或Babel上),您还可以使用Array.from它从类似数组的对象构建数组:

Array.from(document.getElementsByClassName('myClass')).forEach(v=>{

或将类似数组的对象散布到数组中:

[...document.getElementsByClassName('myClass'))].forEach(v=>{

2
@杰arguments是一个。jQuery对象是另一个。您可以自己做一个:var a = {"0": "str1", "1": "str2", length: 2}
2014年

1
在这里,我们再次使用旧的浏览器…将主机对象传递给本机方法将在IE 8及更低版本中失败。也许没有人在乎,但有些人可能在乎。;-)哦,它也不支持getElementsByClassName,但querySelectorAll('.myClass')应该可以。我仍在等待将迭代器添加到NodeList API。:-(
RobG

2
@Jer:作为旁注,如果您出于任何原因打算退出循环,Array.prototype.forEach都不会这样做。如果以后有此要求,请使用标准for循环,或者如果要使用数组对象,请使用Array.prototype.everyor Array.prototype.some(或注意,尽管IE8或更低版本不支持每个/某些)
Nope 2014年

1
@Ian您需要将对象拼接为“类似数组”。在这里比较日志:jsbin.com/sigut/1/edit
DenysSéguret2014年

1
@Ian TBH“类似数组”的定义非常模糊,取决于使用情况。有时,我不包含splice在该定义中,但是当我想变得更像“数组”以能够使用mapfilter等等时,我就将其包含在内。forEach不需要使用简单的迭代splice
DenysSéguret2014年

11

试试这个它应该工作:

<html>
  <head>
    <style type="text/css">
    </style>
  </head>
  <body>
   <div class="myClass">Hello</div>
   <div class="myClass">Hello</div>

<script type="text/javascript">
    var arr = document.getElementsByClassName('myClass');
    console.log(arr);
    console.log(arr[0]);
    arr = [].slice.call(arr); //I have converted the HTML Collection an array
    arr.forEach(function(v,i,a) {
        console.log(v);
    });
</script>


<style type="text/css">
    .myClass {
    background-color: #FF0000;
}
</style>

  </body>
</html>

0

如果要访问特定类的每个元素的ID,可以执行以下操作:

    Array.from(document.getElementsByClassName('myClass')).forEach(function(element) {
        console.log(element.id);
    });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.