HTMLCollection 요소의 For 루프


405

에서 모든 요소의 id를 가져 오려고합니다 HTMLCollectionOf. 다음 코드를 작성했습니다.

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

그러나 콘솔에서 다음과 같은 결과가 나타납니다.

event1
undefined

내가 기대 한 것이 아닙니다. 왜 두 번째 콘솔 출력 undefined이지만 첫 번째 콘솔 출력은 event1무엇입니까?


23
질문이 for ... in 문에 대해 왜 제목이 "foreach"라고 말합니까? 인터넷 검색을 할 때 우연히 여기에 왔습니다.
mxt3

@ mxt3 글쎄, 내 이해에 따르면, 그것은 Java에서 for-each 루프의 변명이었다 (동일하게 작동).

1
@ mxt3 나는 같은 것을 생각했다! 그러나 허용 된 답변을 읽은 후 Array.from ()을 사용하여 foreach 문제를 해결 한이 줄을 찾았습니다.Array.from(document.getElementsByClassName("events")).forEach(function(item) {
HoldOffHunger

답변:


839

원래 질문에 대한 답을 for/in잘못 사용하고 있습니다 . 귀하의 코드 key에서 색인입니다. 따라서 의사 배열에서 값을 얻으려면 수행해야 list[key]하고 ID를 가져와야 list[key].id합니다. 그러나 for/in처음부터이 작업을 수행해서는 안됩니다 .

요약 (2018 년 12 월 추가)

for/innodeList 또는 HTMLCollection을 반복하는 데 사용하지 마십시오 . 이를 피하는 이유는 다음과 같습니다.

최신 브라우저의 모든 최신 버전 (사파리, 파이어 폭스, 크롬, 에지) 모든 지원 for/ofDOM에 대한 반복은 나열 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 등)이 검색되지만 lengthitem속성 도 검색 됩니다. for/in반복은 단순히 HTMLCollection 작동하지 않습니다.


로 HTMLCollection을 반복 할 수없는 이유는 http://jsfiddle.net/jfriend00/FzZ2H/ 를 참조하십시오 for/in.

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 업데이트

이제 코드에 이것을 추가하여 a NodeList및 a 와 함께 ES6 for / of 구문을 사용할 수 있습니다 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 프로토 타입 모두에 연결하여 반복 할 때 Array 반복자를 사용하여 반복하기 때문에 작동합니다.

실무 데모 : http://jsfiddle.net/jfriend00/joy06u4e/ .


2016 년 12 월 ES6의 두 번째 업데이트

2016 년 12 월 현재 Symbol.iteratorChrome v54 및 Firefox v50이 기본적으로 지원되므로 아래 코드는 저절로 작동합니다. 아직 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의 세 번째 업데이트

12 월 2017,이 기능 A의 가장자리 41.16299.15.0의 작품 nodeList에서와 같은 document.querySelectorAll(),하지만 아닌 HTMLCollection처럼 document.getElementsByClassName()당신이 그래서 수동을 위해 가장자리에서 사용하는 반복자를 할당합니다 HTMLCollection. 하나의 컬렉션 유형을 수정했지만 다른 유형은 수정하지 않는 것은 완전히 신비입니다. 그러나 현재 최신 버전의 Edge에서는 document.querySelectorAll()ES6 for/of구문으로 결과를 사용할 수 있습니다 .

이 모두를 테스트 그래서 나는 또한 jsFiddle 위가 업데이트 HTMLCollectionnodeList별도로하고 jsFiddle 자체 출력을 캡처합니다.

2018 년 3 월 ES6 용 네 번째 업데이트

mesqueeeb 당, Symbol.iterator지원이 내장 된 사파리로도 사용할 수 있도록 for (let item of list)중 하나에 대해 document.getElementsByClassName()document.querySelectorAll().

2018 년 4 월 ES6의 다섯 번째 업데이트

분명히 2018 년 가을에 HTMLCollectionwith 를 반복하는 지원 for/of이 Edge 18에 제공 될 것입니다.

2018 년 11 월 ES6 여섯 번째 업데이트

Microsoft Edge v18 (2018 년 가을 Windows 업데이트에 포함)을 사용하면 Edge에서 for / of를 사용하여 HTMLCollection과 NodeList를 모두 반복 할 수 있습니다.

따라서 모든 최신 브라우저에는 for/ofHTMLCollection 및 NodeList 객체의 반복을 기본적으로 지원 합니다.


1
JS가 업데이트 된 매우 자세한 업데이트에 감사드립니다. 이를 통해 초보자는 특정 JS 릴리스에만 적용되는 다른 기사 / 게시물의 맥락에서이 조언을 이해할 수 있습니다.
brownmagik352

탁월한 답변, 놀라운 업데이트 지원. 감사합니다.
cossacksman

79

for/ inon NodeList또는 HTMLCollections를 사용할 수 없습니다 . 그러나 Array.prototype메소드를 .call()전달하고 NodeList또는 HTMLCollection로 전달 하는 한 일부 메소드 를 사용할 수 있습니다 this.

따라서 jfriend00의 for루프에 대한 대안으로 다음을 고려하십시오 .

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

이 기술을 다루는 MDN에 대한 좋은 기사 가 있습니다. 브라우저 호환성에 대한 경고는 다음과 같습니다.

[...] (A와 같은 호스트 개체를 전달 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에서 이미 지원됩니다.


1
아주 좋아요! 이 기술을 사용하여에서 선택된 옵션의 값을 가져 왔습니다 <select multiple>. 예 :[].map.call(multiSelect.selectedOptions, function(option) { return option.value; })
XåpplI'-I0llwlg'I-2

1
ES2015 솔루션을 찾고 있었으므로 for ... of작동하는지 확인해 주셔서 감사 합니다.
Richard Turner

60

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
    });

@DanielM 내가 한 일은 배열과 같은 구조를 얕게 복제하는 것입니다.
mido

감사합니다. 이제 찾고 있던 문서를 찾았습니다. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
DanielM

나는 항상 Array.from보다 훨씬 쉽게 이것을 사용합니다. 성능이 나 메모리 단점이 있는지 궁금합니다. 예를 들어, 테이블 행의 셀을 반복해야하는 경우 [...row.cells].forEach대신 다음을 수행하는 대신row.querySelectorAll('td')
Mojimi

16

이 두 줄을 추가 할 수 있습니다.

HTMLCollection.prototype.forEach = Array.prototype.forEach;
NodeList.prototype.forEach = Array.prototype.forEach;

HTMLCollectiongetElementsByClassNamegetElementsByTagName에 의해 리턴됩니다.

querySelectorAll에 의해 NodeList 가 리턴됩니다.

이와 같이 당신은 forEach를 할 수 있습니다 :

var selections = document.getElementsByClassName('myClass');

/* alternative :
var selections = document.querySelectorAll('.myClass');
*/

selections.forEach(function(element, i){
//do your stuffs
});

이 답변은 매우 효과적입니다. 캐치는 무엇입니까?
Peheje

2
문제는이 솔루션이 IE11에서 작동하지 않는다는 것입니다! 그래도 좋은 해결책입니다.
Rahul Gaba


7

IE 11Firefox 49 에서 forEach를 사용하는 데 문제가 있습니다.

이 같은 해결 방법을 찾았습니다

Array.prototype.slice.call(document.getElementsByClassName("events")).forEach(function (key) {
        console.log(key.id);
    }

IE11을위한 훌륭한 솔루션!
예전

6

대안 Array.from은 사용하는 것입니다Array.prototype.forEach.call

각각: Array.prototype.forEach.call(htmlCollection, i => { console.log(i) });

지도: Array.prototype.map.call(htmlCollection, i => { console.log(i) });

요법 ...


6

forIE9 이상인 경우 es6 기능을 사용하여 루핑 을 피할 이유가 없습니다 .

ES5에는 두 가지 좋은 옵션이 있습니다. 첫째, 당신은 "대출"은 수 ArrayforEach에반 언급 .

그러나 더 나은 ...

를 사용 Object.keys()하면 자동으로 "속성을 소유"하는 필터 있습니다 forEach.

즉, Object.keys본질적으로 a를 for... in사용하는 것과 동일 HasOwnProperty하지만 훨씬 더 부드럽습니다.

var eventNodes = document.getElementsByClassName("events");
Object.keys(eventNodes).forEach(function (key) {
    console.log(eventNodes[key].id);
});

5

2016 년 3 월 현재 Chrome 49.0에서는 다음에 대해 for...of작동합니다 HTMLCollection.

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을 반복하는 방법


4
이는 2016 년 4 월 현재 수정되었습니다 . with을 ( HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];를) 반복 하여 추가 할 필요는 없습니다 . HTMLCollectionfor...of
Expenzor

3

가장자리에

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);
    }
  }
}

2

항상 사용하는 쉬운 해결 방법

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()

1

오래된 ES 버전 (예 : ES5)을 사용하는 경우 다음을 사용할 수 있습니다 as any.

for (let element of elementsToIterate as any) {
      console.log(element);
}

0

당신은 그것을 변경하고 싶습니다

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
}

5
참고로, 이것이 제대로 작동하지 않는 이유에 대한 답변을 참조하십시오. 는 for (key in list)의 몇 가지 속성 반환 HTMLCollection컬렉션에있는 항목이기 위하여 의미되지 않은 있습니다.
jfriend00
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.