[英]For loop for HTMLCollection elements
我正在尝试设置
HTMLCollectionOf<\/code>中所有元素的 get id。
我写了以下代码:
var list = document.getElementsByClassName("events");
console.log(list[0].id);
for (key in list) {
console.log(key.id);
}
在回答原始问题时,您错误地使用了for/in
。 在您的代码中, key
是索引。 因此,要从伪数组中获取值,您必须执行list[key]
并获得 id,您必须执行list[key].id
。 但是,您首先不应该使用for/in
执行此操作。
总结(2018 年 12 月新增)
永远不要使用for/in
来迭代 nodeList 或 HTMLCollection。 避免它的原因如下所述。
所有最新版本的现代浏览器(Safari、Firefox、Chrome、Edge)都支持for/of
迭代 DOM 列表,例如nodeList
或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/in
for/in
用于迭代对象的属性。 这意味着它将返回对象的所有可迭代属性。 虽然它可能看起来适用于数组(返回数组元素或伪数组元素),但它也可以返回对象的其他属性,这些属性不是您对类数组元素所期望的。 而且,你猜怎么着, HTMLCollection
或nodeList
对象都可以有其他属性,这些属性将通过for/in
迭代返回。 我只是在 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
、 1
和2
。
以下是浏览器在 2015 年至 2018 年期间如何演变的演变,为您提供了其他迭代方式。 现代浏览器现在不需要这些,因为您可以使用上述选项。
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 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。 这是有效的,因为它将 Array 迭代器附加到 NodeList 和 HTMLCollection 原型,以便当 for/of 迭代它们时,它使用 Array 迭代器来迭代它们。
工作演示: http : //jsfiddle.net/jfriend00/joy06u4e/ 。
2016 年 12 月 ES6 的第二次更新
截至 2016 年 12 月,Chrome v54 和 Firefox v50 已内置Symbol.iterator
支持,因此以下代码可以自行运行。 它尚未内置于 Edge 中。
var list = document.getElementsByClassName("events");
for (let item of list) {
console.log(item.id);
}
工作演示(在 Chrome 和 Firefox 中): http : //jsfiddle.net/jfriend00/3ddpz8sp/
2017 年 12 月 ES6 的第三次更新
截至 2017 年 12 月,此功能在 Edge 41.16299.15.0 中适用于document.querySelectorAll()
的nodeList
,但不适用于document.getElementsByClassName()
的HTMLCollection
,因此您必须手动分配迭代器以在 Edge 中使用它一个HTMLCollection
。 为什么他们会修复一种集合类型,而不是另一种,这完全是个谜。 但是,您现在至少可以在 Edge 的当前版本中使用带有 ES6 for/of
语法的document.querySelectorAll()
的结果。
我还更新了上面的 jsFiddle,因此它分别测试HTMLCollection
和nodeList
并在 jsFiddle 本身中捕获输出。
2018 年 3 月 ES6 的第四次更新
根据 mesqueeeb, Symbol.iterator
支持也已内置到 Safari 中,因此您可以将for (let item of list)
用于document.getElementsByClassName()
或document.querySelectorAll()
。
2018 年 4 月 ES6 第五次更新
显然,Edge 18 将在 2018 年秋季支持使用for/of
迭代HTMLCollection
。
2018 年 11 月 ES6 第六次更新
我可以确认,使用 Microsoft Edge v18(包含在 2018 年秋季 Windows 更新中),您现在可以在 Edge 中使用 for/of 迭代 HTMLCollection 和 NodeList。
因此,现在所有现代浏览器都包含对 HTMLCollection 和 NodeList 对象for/of
迭代for/of
迭代的本机支持。
您不能在NodeList
或HTMLCollection
上使用for
/ in
。 但是,您可以使用一些Array.prototype
方法,只要您.call()
它们并将NodeList
或HTMLCollection
作为this
HTMLCollection
。
因此,请考虑将以下内容作为jfriend00 的for
循环的替代方案:
var list= document.getElementsByClassName("events");
[].forEach.call(list, function(el) {
console.log(el.id);
});
MDN 上有一篇很好的文章介绍了这种技术。 请注意他们关于浏览器兼容性的警告:
[...] 将主机对象(如
NodeList
)作为this
传递给本机方法(如forEach
)并不能保证在所有浏览器中都能正常工作,并且在某些浏览器中会失败。
因此,虽然这种方法很方便,但for
循环可能是与浏览器最兼容的解决方案。
更新(2014 年 8 月 30 日):最终您将能够将ES6 for
/ of
!
var list = document.getElementsByClassName("events");
for (const 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)
例如:-
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;
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
});
Array.from
替代Array.from
是使用Array.prototype.forEach.call
forEach: Array.prototype.forEach.call(htmlCollection, i => { console.log(i) });
地图: Array.prototype.map.call(htmlCollection, i => { console.log(i) });
等等...
没有理由使用ES6功能逃跑for
,如果你在IE9以上循环。
在 ES5 中,有两个不错的选择。 首先,你可以像埃文提到的那样“借用” Array
的forEach
。
但更好的是...
Object.keys()
,它确实有forEach
和过滤器来自动“拥有属性”。 也就是说, Object.keys
本质上等同for... in
使用HasOwnProperty
执行for... in
,但要平滑得多。
var eventNodes = document.getElementsByClassName("events");
Object.keys(eventNodes).forEach(function (key) {
console.log(eventNodes[key].id);
});
我在IE 11和Firefox 49 中使用 forEach 时遇到问题
我找到了这样的解决方法
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];
将for...of
与NodeList
一起使用也是必要的:
NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
我相信/希望for...of
很快就会在没有上述解决方法的情况下工作。 开放问题在这里:
https://bugs.chromium.org/p/chromium/issues/detail?id=401699
更新:请参阅下面的 Expenzor 评论:截至 2016 年 4 月已修复此问题。您无需添加 HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; 使用 for...of 迭代 HTMLCollection
边缘
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);
}
}
}
我一直使用的简单解决方法
let list = document.getElementsByClassName("events");
let listArr = Array.from(list)
在此之后,您可以在选择上运行任何所需的 Array 方法
listArr.map(item => console.log(item.id))
listArr.forEach(item => console.log(item.id))
listArr.reverse()
如果您使用旧版本的 ES,(例如 ES5),您可以使用as any
:
for (let element of elementsToIterate as any) {
console.log(element);
}
你想把它改成
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
}
你也可以这样做:
let elements = document.getElementsByClassName("classname");
for(let index in elements) {
if(index <= elements.length) {
console.log(elements[index]);
}
}
let elements = document.getElementsByClassName("classname"); for (let index in elements) { if (index <= elements.length) { console.log(elements[index]); } }
<div class="classname"> element 1 </div> <div class="classname"> element 2 </div> <div class="classname"> element 3 </div>
或者
let elements = document.getElementsByClassName("classname");
for(let ele of elements) {
console.log(ele);
}
let elements = document.getElementsByClassName("classname"); for (let ele of elements) { console.log(ele); }
<div class="classname"> element 1 </div> <div class="classname"> element 2 </div> <div class="classname"> element 3 </div> <div class="classname"> element 4 </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.