Javascript HTMLCollection元素的For循环

Javascript HTMLCollection元素的For循环,javascript,dom,Javascript,Dom,我正在尝试设置HTMLCollectionOf中所有元素的get id。我编写了以下代码: var list = document.getElementsByClassName("events"); console.log(list[0].id); for (key in list) { console.log(key.id); } 但我在控制台中得到了以下输出: event1 undefined 这不是我所期望的。为什么第二个控制台输出未定义,而第一个控制台输出是event1?要将

我正在尝试设置
HTMLCollectionOf
中所有元素的get id。我编写了以下代码:

var list = document.getElementsByClassName("events");
console.log(list[0].id);
for (key in list) {
    console.log(key.id);
}
但我在控制台中得到了以下输出:

event1
undefined

这不是我所期望的。为什么第二个控制台输出
未定义
,而第一个控制台输出是
event1

要将其更改为

var list= document.getElementsByClassName("events");
console.log(list[0].id); //first console output
for (key in list){
    console.log(list[key].id); //second console output
}

在回答原始问题时,您错误地使用了
for/In
。在代码中,
是索引。因此,要从伪数组中获取值,必须执行
list[key]
,要获取id,必须执行
list[key].id
。但是,您首先不应该使用
for/in
来执行此操作

摘要(于2018年12月添加)

永远不要使用
for/in
来迭代节点列表或HTMLCollection。避免这种情况的原因如下所述

所有最新版本的现代浏览器(Safari、Firefox、Chrome、Edge)都支持对DOM列表进行迭代,例如节点列表或HTMLCollection

下面是一个例子:

var list = document.getElementsByClassName("events");
for (let item of list) {
    console.log(item.id);
}
为了包括旧浏览器(包括IE等),这将在任何地方都适用:

var list= document.getElementsByClassName("events");
for (var i = 0; i < list.length; i++) {
    console.log(list[i].id); //second console output
}
希望现在您可以了解为什么要使用
for(var i=0;i
,这样您就可以在迭代中得到
0
1
2


下面是浏览器在2015-2018年间的演变,为您提供了更多的迭代方式。现在,现代浏览器中不需要这些选项,因为您可以使用上述选项

2015年ES6的更新

添加到ES6的是
Array.from()
,它将类似数组的结构转换为实际数组。这样就可以像下面这样直接枚举列表:

"use strict";

Array.from(document.getElementsByClassName("events")).forEach(function(item) {
   console.log(item.id);
});
 let elements = document.getElementsByClassName("classname");
 for(let index in  elements) {
   if(index <= elements.length) {
        console.log(elements[index]);
  }
}
工作演示(截至2016年4月在Firefox、Chrome和Edge中):


2016年ES6的更新

您现在可以将ES6 for/of构造与
NodeList
HTMLCollection
一起使用,只需将其添加到代码中即可:

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
然后,您可以执行以下操作:

var list = document.getElementsByClassName("events");
for (var item of list) {
    console.log(item.id);
}
这适用于当前版本的Chrome、Firefox和Edge。这是因为它将数组迭代器附加到NodeList和HTMLCollection原型上,因此当for/of对它们进行迭代时,它使用数组迭代器对它们进行迭代

工作演示:


2016年12月第二次更新ES6

截至2016年12月,
Symbol.iterator
支持已内置到Chrome v54和Firefox v50中,因此下面的代码可以自行工作。它尚未内置于Edge

var list = document.getElementsByClassName("events");
for (let item of list) {
    console.log(item.id);
}
工作演示(在Chrome和Firefox中):

2017年12月第三次更新ES6

截至2017年12月,此功能在Edge 41.16299.15.0中适用于
节点列表
,如
文档.querySelectorAll()
,但不是
文档.getElementsByClassName()
中的
HTMLCollection
中的
HTMLCollection
,因此必须手动分配迭代器才能在Edge中用于
HTMLCollection
。他们为什么要修复一种收藏类型,而不修复另一种,这完全是个谜。但是,在当前版本的Edge now中,您至少可以将
document.querySelectorAll()的结果与ES6
for/of
语法一起使用

我还更新了上面的JSFIDLE,以便它分别测试
HTMLCollection
nodeList
,并捕获JSFIDLE本身的输出

2018年3月ES6的第四次更新

根据mesqueeeb,
Symbol.iterator
支持也已内置到Safari中,因此您可以将
用于(列表项)
用于
document.getElementsByClassName()
document.queryselectoral()

2018年4月第五次ES6更新

显然,对
HTMLCollection
for/of
进行迭代的支持将在2018年秋季到达Edge 18

2018年11月第六次ES6更新

我可以确认,使用Microsoft Edge v18(包含在2018年秋季Windows更新中),您现在可以在Edge中使用for/of迭代HTMLCollection和节点列表


因此,现在所有现代浏览器都包含了对HTMLCollection和NodeList对象的迭代的本机支持。

您不能在
节点列表
HTMLCollection
上的
中使用
。但是,您可以使用一些
Array.prototype
方法,只要您
.call()
并将
节点列表
HTMLCollection作为
this
传入即可

因此,请考虑以下选项:

有一个很好的例子,涵盖了这项技术。注意他们关于浏览器兼容性的警告:

[…]将主机对象(如
节点列表
)作为
本机方法(如
forEach
)的此
不保证在中工作 所有的浏览器,并且已知在某些情况下失败

因此,虽然这种方法很方便,但是
for
循环可能是最兼容浏览器的解决方案

更新(2014年8月30日):最终您将能够使用


Chrome和Firefox的最新版本已经支持它。

截至2016年3月,在Chrome 49.0中,
for…of
适用于
HTMLCollection

this.headers = this.getElementsByTagName("header");

for (var header of this.headers) {
    console.log(header); 
}

但只有在使用
for…之前应用以下变通方法时,它才有效:

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
for…of
节点列表一起使用时,也需要这样做:

NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
我相信/希望没有上述解决办法,
for…of
将很快奏效。公开问题如下:


更新:请参见下面Expenzor的评论:该问题已于2016年4月得到解决。您不需要添加HTMLCollection.prototype[Symbol.iterator]=Array.prototype[Symbol.iterato
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
let someCollection = document.querySelectorAll(someSelector)
[...someCollection].forEach(someFn) 
//or
Array.from(collection).forEach(someFn)
    navDoms = document.getElementsByClassName('nav-container');
    Array.from(navDoms).forEach(function(navDom){
     //implement function operations
    });
HTMLCollection.prototype.forEach = Array.prototype.forEach;
NodeList.prototype.forEach = Array.prototype.forEach;
var selections = document.getElementsByClassName('myClass');

/* alternative :
var selections = document.querySelectorAll('.myClass');
*/

selections.forEach(function(element, i){
//do your stuffs
});
Array.prototype.slice.call(document.getElementsByClassName("events")).forEach(function (key) {
        console.log(key.id);
    }
if(!NodeList.prototype.forEach) {
  NodeList.prototype.forEach = function(fn, scope) {
    for(var i = 0, len = this.length; i < len; ++i) {
      fn.call(scope, this[i], i, this);
    }
  }
}
var eventNodes = document.getElementsByClassName("events");
Object.keys(eventNodes).forEach(function (key) {
    console.log(eventNodes[key].id);
});
for (let element of elementsToIterate as any) {
      console.log(element);
}

let list = document.getElementsByClassName("events");
let listArr = Array.from(list)
listArr.map(item => console.log(item.id))
listArr.forEach(item => console.log(item.id))
listArr.reverse()
 let elements = document.getElementsByClassName("classname");
 for(let index in  elements) {
   if(index <= elements.length) {
        console.log(elements[index]);
  }
}