问题描述
我正在尝试设置 HTMLCollectionOf
中所有元素的 get id.我写了以下代码:
var list = document.getElementsByClassName("events");控制台日志(列表[0].id);对于(列表中的键){控制台日志(key.id);}
但我在控制台得到以下输出:
event1不明确的
这不是我所期望的.为什么第二个控制台输出 undefined
而第一个控制台输出是 event1
?
针对最初的问题,您错误地使用了 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(让列表项){控制台.log(item.id);}
要包括旧版浏览器(包括 IE 之类的东西),这将适用于任何地方:
var list = document.getElementsByClassName("events");for (var i = 0; i < list.length; i++) {console.log(list[i].id);//第二个控制台输出}
为什么不应该使用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
迭代将返回这些项目(对象的所有可迭代属性):
希望现在你能明白为什么要使用 for (var i = 0; i < list.length; i++)
代替,这样你就可以得到 0
, 1
和 2
在您的迭代中.
浏览器支持 NodeList 和 HTMLCollection 迭代的演进
以下是浏览器在 2015 年至 2018 年期间的演变过程,为您提供了其他迭代方式.现代浏览器现在不需要这些,因为您可以使用上述选项.
2015 年 ES6 更新
添加到 ES6 的是 Array.from()
它将把类似数组的结构转换为实际的数组.这允许像这样直接枚举列表:
严格使用";Array.from(document.getElementsByClassName("events")).forEach(function(item) {控制台.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 列表项) {控制台.log(item.id);}
这适用于当前版本的 Chrome、Firefox 和 Edge.这是有效的,因为它将 Array 迭代器附加到 NodeList 和 HTMLCollection 原型,以便当 for/of 迭代它们时,它使用 Array 迭代器来迭代它们.
工作演示:http://jsfiddle.net/jfriend00/joy06u4e/.
2016 年 12 月对 ES6 的第二次更新
截至 2016 年 12 月,Symbol.iterator
支持已内置于 Chrome v54 和 Firefox v50,因此下面的代码可以自行运行.它尚未内置于 Edge.
var list = document.getElementsByClassName("events");for(让列表项){控制台.log(item.id);}
工作演示(在 Chrome 和 Firefox 中):http://jsfiddle.net/jfriend00/3ddpz8sp/一个>
2017 年 12 月针对 ES6 的第三次更新
截至 2017 年 12 月,此功能在 Edge 41.16299.15.0 中适用于 nodeList
,如 document.querySelectorAll()
,但不适用于 HTMLCollection
与 document.getElementsByClassName()
中的一样,因此您必须手动分配迭代器以在 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
迭代的本机支持.
I'm trying to set get id of all elements in an HTMLCollectionOf
. 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
?
In response to the original question, you are using for/in
incorrectly. In your code, key
is the index. 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
. But, you should not be doing this with for/in
in the first place.
Summary (added in Dec 2018)
Do not ever use for/in
to iterate a nodeList or an 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
.
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:
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
is meant for iterating the properties of an object. 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. 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. The for/in
iteration simply won't work for an HTMLCollection.
See http://jsfiddle.net/jfriend00/FzZ2H/ for why you can't iterate an HTMLCollection with for/in
.
In Firefox, your for/in
iteration would return these items (all the iterable properties of the object):
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.
Evolution of Browser Support for NodeList and HTMLCollection iteration
Following below is an evolution of how browsers have evolved through the time period 2015-2018 giving you additional ways to iterate. None of these are now needed in modern browsers since you can use the options described above.
Update for ES6 in 2015
Added to ES6 is Array.from()
that will convert an array-like structure to an actual array. 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/
Update for ES6 in 2016
You can now use the ES6 for/of construct with a NodeList
and an HTMLCollection
by just adding this to your code:
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. 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.
Working demo: http://jsfiddle.net/jfriend00/joy06u4e/.
Second Update for ES6 in Dec 2016
As of Dec 2016, Symbol.iterator
support has been built-in to Chrome v54 and Firefox v50 so the code below works by itself. It is not yet built-in for 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/
Third Update for ES6 in Dec 2017
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
. 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.
I've also updated the above jsFiddle so it tests both HTMLCollection
and nodeList
separately and captures the output in the jsFiddle itself.
Fourth Update for ES6 in Mar 2018
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()
.
Fifth Update for ES6 in Apr 2018
Apparently, support for iterating an HTMLCollection
with for/of
will be coming to Edge 18 in Fall 2018.
Sixth Update for ES6 in Nov 2018
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.
So, now all modern browsers contain native support for for/of
iteration of both the HTMLCollection and NodeList objects.
这篇关于HTMLCollection 元素的 For 循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!