用于循环的HTMLCollection元素

我试图设置获取HTMLCollection中的所有元素的ID。 我写了下面的代码:

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

但是我在控制台中得到了以下输出:

 event1 undefined 

这不是我所期望的。 为什么second console output undefined但第first console outputevent1

Eeek。 您不应该使用for/in迭代nodeListHTMLCollection ,而且当您执行迭代时,您需要实际使用迭代中的索引从列表中检索值。

你应该像这样迭代它:

 var list= document.getElementsByClassName("events"); for (var i = 0; i < list.length; i++) { console.log(list[i].id); //second console output } 

for/in意味着迭代对象的属性。 这并不意味着迭代HTMLCollection所在的数组或类似数组的对象。 我只是在Chrome浏览器中试过,并按迭代的方式迭代,它将检索列表中的项目(索引0,1,2等),但也会检索lengthitem属性。 for/in迭代不能用于HTMLCollection。


查看http://jsfiddle.net/jfriend00/FzZ2H/为什么你不能用;for/in迭代HTMLCollection。

在Firefox中, for/in迭代将返回这些项目(对象的所有可迭代属性):

 0 1 2 item namedItem @@iterator length 

希望现在你可以看到为什么要使用for (var i = 0; i < list.length; i++)所以你只需要在你的迭代中获得02


2015年更新ES6

添加到ES6是Array.from() ,将数组类似的结构转换为实际的数组。 这允许直接枚举列表如下:

 "use strict"; Array.from(document.getElementsByClassName("events")).forEach(function(item) { console.log(item.id); }); 

工作演示(截至2016年4月的Firefox,Chrome和Edge): https : //jsfiddle.net/jfriend00/8ar4xn2s/


2016年更新ES6

你现在可以使用ES6来构buildNodeListHTMLCollection ,只需将它添加到你的代码中:

 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) { log(item.id); } 

这适用于当前版本的Chrome,Firefox和Edge。

工作演示: http : //jsfiddle.net/jfriend00/joy06u4e/ 。


ES6在2016年12月的第二次更新

截至2016年12月, Symbol.iterator支持已经Symbol.iterator到Chrome v54和Firefox v50中,因此下面的代码可以自行运行。 Edge还没有内置。

 var list = document.getElementsByClassName("events"); for (var item of list) { log(item.id); } 

工作演示(在Chrome和Firefox中): http : //jsfiddle.net/jfriend00/3ddpz8sp/

您不能在NodeListHTMLCollection上使用for / in 。 不过,你可以使用一些Array.prototype方法,只要你调用它们并传入NodeList或者HTMLCollection就可以this

所以考虑以下几点作为jfriend00的for循环的替代:

 var list= document.getElementsByClassName("events"); [].forEach.call(list, function(el) { console.log(el.id); }); 

MDN上有一篇关于这项技术的文章。 注意他们关于浏览器兼容性的警告:

将一个主机对象(如NodeList )传递给一个本地方法(如forEach )并不能保证在所有的浏览器中都能正常工作,而且在某些情况下已知会失败。

所以虽然这种方法很方便,但for循环可能是最符合浏览器的解决scheme。

更新(2014年8月30日):最终你可以使用ES6 for / of

 var list = document.getElementsByClassName("events"); for (el of list) console.log(el.id); 

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

在ES6中,你可以做一些类似于[...collection]或者Array.from(collection)

 let someCollection = document.querySelectorAll(someSelector) [...someCollection].forEach(someFn) //or Array.from(collection).forEach(someFn) 

你可以添加这两行:

 HTMLCollection.prototype.forEach = Array.prototype.forEach; NodeList.prototype.forEach = Array.prototype.forEach; 

HTMLCollection是由getElementsByClassNamegetElementsByTagName返回的

NodeList是由querySelectorAll返回的

像这样你可以做一个forEach:

 var selections = document.getElementsByClassName('myClass'); /* alternative : var selections = document.querySelectorAll('.myClass'); */ selections.forEach(function(element, i){ //do your stuffs }); 

我在IE 11Firefox 49中使用forEach时遇到了问题

我find了这样的解决方法

 Array.prototype.slice.call(document.getElementsByClassName("events")).forEach(function (key) { console.log(key.id); } 

截至2016年3月,在Chrome 49.0中,针对HTMLCollection for...of作品:

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

看到这里的文件 。

但只有使用for...of 之前应用以下解决方法才有效

 HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; 

NodeList一样使用for...of也是必须的:

 NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; 

如果没有上述解决方法,我相信/希望能够很快的工作。 公开的问题在这里:

https://bugs.chromium.org/p/chromium/issues/detail?id=401699

更新:查看下面的Expenzor的评论: 这已经在2016年4月份被修复了。你不需要添加HTMLCollection.prototype [Symbol.iterator] = Array.prototype [Symbol.iterator]; 通过…来遍历一个HTMLCollection

你想改变它

 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 } 

边缘

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