HTMLCollection元素的For循环

本文翻译自:For loop for HTMLCollection elements

I'm trying to set get id of all elements in an HTMLCollectionOf . 我正在尝试设置HTMLCollectionOf中所有元素的获取ID。 I wrote the following code: 我写了以下代码:

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

But I got the following output in console: 但是我在控制台中得到以下输出:

event1
undefined

which is not what I expected. 这不是我所期望的。 Why is the second console output undefined but the first console output is event1 ? 为什么第二个控制台输出undefined但第一个控制台输出是event1


#1楼

参考:https://stackoom.com/question/1XTR5/HTMLCollection元素的For循环


#2楼

You want to change it to 您想要将其更改为

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
}

#3楼

In response to the original question, you are using for/in incorrectly. 在回答原始问题时,您使用for/in不正确的for/in In your code, key is the index. 在您的代码中, key是索引。 So, to get the value from the pseudo-array, you'd have to do list[key] and to get the id, you'd do list[key].id . 因此,要从伪数组中获取值,您必须执行list[key]并获取ID,您必须执行list[key].id But, you should not be doing this with for/in in the first place. 但是,您不应该首先使用for/in进行此操作。

Summary (added in Dec 2018) 摘要(于2018年12月新增)

Do not ever use for/in to iterate a nodeList or an HTMLCollection. 永远不要使用for/in来迭代nodeList或HTMLCollection。 The reasons to avoid it are described below. 避免这种情况的原因如下所述。

All recent versions of modern browsers (Safari, Firefox, Chrome, Edge) all support for/of iteration on DOM lists such nodeList or HTMLCollection . 现代浏览器的所有最新版本(Safari,Firefox,Chrome,Edge)都支持DOM列表上for/of迭代,例如nodeListHTMLCollection

Here's an example: 这是一个例子:

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

To include older browsers (including things like IE), this will work everywhere: 要包括较旧的浏览器(包括IE之类的东西),它将在任何地方都适用:

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

Explanation For Why You Should Not Use for/in 为什么不应该for/in使用的解释

for/in is meant for iterating the properties of an object. for/in用于迭代对象的属性。 That means it will return all iterable properties of an object. 这意味着它将返回对象的所有可迭代属性。 While it may appear to work for an array (returning array elements or pseudo-array elements), it can also return other properties of the object that are not what you are expecting from the array-like elements. 尽管它似乎可以用于数组(返回数组元素或伪数组元素),但它也可以返回对象的其他属性,这些属性不是您希望从类似数组的元素中获得的。 And, guess what, an HTMLCollection or nodeList object can both have other properties that will be returned with a for/in iteration. 而且,猜想是什么, HTMLCollectionnodeList对象都可以具有其他属性,这些属性将通过for/in迭代返回。 I just tried this in Chrome and iterating it the way you were iterating it will retrieve the items in the list (indexes 0, 1, 2, etc...), but also will retrieve the length and item properties. 我只是在Chrome中尝试了此操作,然后以您迭代的方式对其进行了迭代,它将检索列表中的项目(索引0、1、2等...),但还将检索lengthitem属性。 The for/in iteration simply won't work for an HTMLCollection. for/in迭代对于HTMLCollection根本不起作用。


See http://jsfiddle.net/jfriend00/FzZ2H/ for why you can't iterate an HTMLCollection with for/in . 有关为什么无法使用for/in迭代HTMLCollection的信息,请参见http://jsfiddle.net/jfriend00/FzZ2H/

In Firefox, your for/in iteration would return these items (all the iterable properties of the object): 在Firefox中, for/in迭代将返回以下项(对象的所有可迭代属性):

0
1
2
item
namedItem
@@iterator
length

Hopefully, now you can see why you want to use for (var i = 0; i < list.length; i++) instead so you just get 0 , 1 and 2 in your iteration. 我们希望,现在你可以看到为什么要使用for (var i = 0; i < list.length; i++)代替你只会得到012中的迭代。


Following below is an evolution of how browsers have evolved through the time period 2015-2018 giving you additional ways to iterate. 以下是浏览器在2015-2018年期间的演变方式的演变,为您提供了其他迭代方式。 None of these are now needed in modern browsers since you can use the options described above. 由于您可以使用上述选项,因此现代浏览器现在不需要这些。

Update for ES6 in 2015 2015年ES6更新

Added to ES6 is Array.from() that will convert an array-like structure to an actual array. ES6中添加了Array.from() ,它将把类似数组的结构转换为实际数组。 That allows one to enumerate a list directly like this: 这样就可以像这样直接枚举列表:

"use strict";

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

Working demo (in Firefox, Chrome, and Edge as of April 2016): https://jsfiddle.net/jfriend00/8ar4xn2s/ 工作演示(截至2016年4月在Firefox,Chrome和Edge中): https : //jsfiddle.net/jfriend00/8ar4xn2s/


Update for ES6 in 2016 2016年ES6更新

You can now use the ES6 for/of construct with a NodeList and an HTMLCollection by just adding this to your code: 现在,只需将ES6 for / of构造添加到代码中,即可将其与NodeListHTMLCollection使用:

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

Then, you can do: 然后,您可以执行以下操作:

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

This works in the current version of Chrome, Firefox, and Edge. 在当前版本的Chrome,Firefox和Edge中有效。 This works because it attaches the Array iterator to both the NodeList and HTMLCollection prototypes so that when for/of iterates them, it uses the Array iterator to iterate them. 之所以行之有效,是因为它将Array迭代器附加到NodeList和HTMLCollection原型上,以便当for / of对其进行迭代时,它使用Array迭代器对其进行迭代。

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


Second Update for ES6 in Dec 2016 ES6的第二次更新于2016年12月

As of Dec 2016, Symbol.iterator support has been built-in to Chrome v54 and Firefox v50 so the code below works by itself. 截至2016年12月,Chrome v54和Firefox v50内置了Symbol.iterator支持,因此以下代码可独立运行。 It is not yet built-in for Edge. Edge尚未内置。

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

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

Third Update for ES6 in Dec 2017 ES6的第三次更新(2017年12月)

As of Dec. 2017, this capability works in Edge 41.16299.15.0 for a nodeList as in document.querySelectorAll() , but not an HTMLCollection as in document.getElementsByClassName() so you have to manually assign the iterator to use it in Edge for an HTMLCollection . 截至2017年12月,此功能在Edge 41.16299.15.0中可用于document.querySelectorAll()nodeList ,但不适用于document.getElementsByClassName()HTMLCollection ,因此您必须手动分配迭代器才能在Edge中使用一个HTMLCollection It is a total mystery why they'd fix one collection type, but not the other. 为什么要修复一种收集类型而不解决另一种收集类型,这完全是个谜。 But, you can at least use the result of document.querySelectorAll() with ES6 for/of syntax in current versions of Edge now. 但是,现在至少可以在当前版本的Edge中将带有ES6的document.querySelectorAll()结果for/of语法。

I've also updated the above jsFiddle so it tests both HTMLCollection and nodeList separately and captures the output in the jsFiddle itself. 我还更新了上面的jsFiddle,因此它分别测试了HTMLCollectionnodeList并捕获了jsFiddle本身的输出。

Fourth Update for ES6 in Mar 2018 ES6的第四次更新于2018年3月

Per mesqueeeb, Symbol.iterator support has been built-in to Safari too, so you can use for (let item of list) for either document.getElementsByClassName() or document.querySelectorAll() . 对于每个中队, Symbol.iterator支持也已内置到Safari中,因此您可以将document.getElementsByClassName()document.querySelectorAll() for (let item of list) document.querySelectorAll()

Fifth Update for ES6 in Apr 2018 ES6的第五次更新于2018年4月

Apparently, support for iterating an HTMLCollection with for/of will be coming to Edge 18 in Fall 2018. 显然,对for/of迭代HTMLCollection支持将在2018年秋季的Edge 18中提供。

Sixth Update for ES6 in Nov 2018 ES6的第六次更新于2018年11月

I can confirm that with Microsoft Edge v18 (that is included in the Fall 2018 Windows Update), you can now iterate both an HTMLCollection and a NodeList with for/of in Edge. 我可以确认使用Microsoft Edge v18(包含在2018年秋季的Windows Update中)现在可以在Edge中使用for / of迭代HTMLCollection和NodeList。

So, now all modern browsers contain native support for for/of iteration of both the HTMLCollection and NodeList objects. 因此,现在所有现代浏览器都原生支持HTMLCollection和NodeList对象的for/of迭代。


#4楼

You can't use for / in on NodeList s or HTMLCollection s. 您不能使用for / inNodeList秒或HTMLCollection秒。 However, you can use some Array.prototype methods, as long as you .call() them and pass in the NodeList or HTMLCollection as this . 但是,你可以使用一些Array.prototype方法,只要你.call()他们,并通过在NodeListHTMLCollection作为this

So consider the following as an alternative to jfriend00's for loop : 因此,请考虑以下内容作为jfriend00的for循环的替代方法:

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

There's a good article on MDN that covers this technique. 在MDN上有一篇很好的文章介绍了该技术。 Note their warning about browser compatibility though: 请注意他们关于浏览器兼容性的警告:

[...] passing a host object (like a NodeList ) as this to a native method (such as forEach ) is not guaranteed to work in all browsers and is known to fail in some. 不能将主机对象(例如NodeListthis传递给本机方法(例如forEach ),不能保证在所有浏览器中都能正常工作,并且已知在某些浏览器中会失败。

So while this approach is convenient, a for loop may be the most browser-compatible solution. 因此,尽管这种方法很方便,但是for循环可能是与浏览器最兼容的解决方案。

Update (Aug 30, 2014): Eventually you'll be able to use ES6 for / of ! 更新(2014年8月30日):最终,您将可以for / of使用ES6

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

It's already supported in recent versions of Chrome and Firefox. Chrome和Firefox的最新版本已支持该功能。


#5楼

As of March 2016, in Chrome 49.0, for...of works for HTMLCollection : 截至2016年3月,在Chrome 49.0中, for...of用于HTMLCollection for...of

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

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

See here the documentation . 请参阅此处的文档

But it only works if you apply the following workaround before using the for...of : 但是,只有使用for...of 之前应用以下变通方法时它才有效:

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

The same is necessary for using for...of with NodeList : for...ofNodeList一起使用同样需要:

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

I believe/hope for...of will soon work without the above workaround. 我相信/希望for...of很快能在没有上述解决方法的情况下工作。 The open issue is here: 未解决的问题在这里:

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

Update: See Expenzor's comment below: This has been fixed as of April 2016. You don't need to add HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; 更新:请参阅下面的Expenzor注释: 截至2016年4月,此问题已得到修复。您无需添加HTMLCollection.prototype [Symbol.iterator] = Array.prototype [Symbol.iterator]; to iterate over an HTMLCollection with for...of 遍历带有... of的HTMLCollection


#6楼

In ES6, you could do something like [...collection] , or Array.from(collection) , 在ES6中,您可以执行[...collection]Array.from(collection)

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

Eg:- 例如:-

    navDoms = document.getElementsByClassName('nav-container');
    Array.from(navDoms).forEach(function(navDom){
     //implement function operations
    });
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值