用于循环的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 output
是event1
?
Eeek。 您不应该使用for/in
迭代nodeList
或HTMLCollection
,而且当您执行迭代时,您需要实际使用迭代中的索引从列表中检索值。
你应该像这样迭代它:
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等),但也会检索length
和item
属性。 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++)
所以你只需要在你的迭代中获得0
和2
。
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来构buildNodeList
和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) { 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/
您不能在NodeList
或HTMLCollection
上使用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是由getElementsByClassName和getElementsByTagName返回的
NodeList是由querySelectorAll返回的
像这样你可以做一个forEach:
var selections = document.getElementsByClassName('myClass'); /* alternative : var selections = document.querySelectorAll('.myClass'); */ selections.forEach(function(element, i){ //do your stuffs });
我在IE 11和Firefox 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); } } }