繁体   English   中英

"HTMLCollection 元素的 for 循环"

[英]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 列表,例如nodeListHTMLCollection

下面是一个例子:

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用于迭代对象的属性。 这意味着它将返回对象的所有可迭代属性。 虽然它可能看起来适用于数组(返回数组元素或伪数组元素),但它也可以返回对象的其他属性,这些属性不是您对类数组元素所期望的。 而且,你猜怎么着, HTMLCollectionnodeList对象都可以有其他属性,这些属性将通过for/in迭代返回。 我只是在 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++)代替,因此您在迭代中只得到012


以下是浏览器在 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 构造与NodeListHTMLCollection使用:

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,因此它分别测试HTMLCollectionnodeList并在 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迭代的本机支持。

您不能在NodeListHTMLCollection上使用for / in 但是,您可以使用一些Array.prototype方法,只要您.call()它们并将NodeListHTMLCollection作为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;

HTMLCollectiongetElementsByClassNamegetElementsByTagName返回

NodeListquerySelectorAll返回

像这样你可以做一个 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 中,有两个不错的选择。 首先,你可以像埃文提到的那样“借用” ArrayforEach

但更好的是...

使用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 11Firefox 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...ofNodeList一起使用也是必要的:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM