JS : Array.forEach를 사용하여 getElementsByClassName의 결과를 반복


240

일부 DOM 요소를 반복하고 싶습니다.이 작업을 수행하고 있습니다.

document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
  //do stuff
});

하지만 오류가 발생합니다.

document.getElementsByClassName ( "myclass"). forEach는 함수가 아닙니다

나는 모두 알고, 그래서 나는 파이어 폭스 3를 사용하고 getElementsByClassName그리고 Array.forEach존재한다. 이것은 잘 작동합니다.

[2, 5, 9].forEach( function(element, index, array) {
  //do stuff
});

getElementsByClassName배열 의 결과 입니까? 그렇지 않다면 무엇입니까?

답변:


384

제 바와 같이 DOM4에 지정된 , 그것은이다 HTMLCollection(적어도, 최신 브라우저에서. 이전 브라우저는 반환 NodeList).

모든 최신 브라우저 (다른 IE <= 8)에서 Array의 forEach메서드를 호출 하여 요소 목록 ( HTMLCollection또는 NodeList)을 this값 으로 전달할 수 있습니다 .

var els = document.getElementsByClassName("myclass");

Array.prototype.forEach.call(els, function(el) {
    // Do stuff here
    console.log(el.tagName);
});

// Or
[].forEach.call(els, function (el) {...});

ES6을 사용할 수있는 좋은 위치에 있다면 (예 : Internet Explorer를 안전하게 무시하거나 ES5 트랜스 파일러를 사용하는 경우) 다음을 사용할 수 있습니다 Array.from.

Array.from(els).forEach((el) => {
    // Do stuff here
    console.log(el.tagName);
});

29
먼저 배열로 변환 할 필요가 없습니다. 그냥 사용하십시오 [].forEach.call(elsArray, function () {...}).
kay-SE는 사악하다

1
NodeList가 아닙니다. 배열과 같은 객체입니다. 인스턴스 유형이 없다고 생각합니다. querySelectorAll메소드는 NodeList를 반환합니다.
Maksim Vi.

2
@MaksimVi. 당신은 절대적으로 맞습니다 : DOM4 document.getElementsByClassName()HTMLCollection(매우 유사하지만 NodeList는 아닙니다)를 반환하도록 지정합니다 . 실수를 지적 해 주셔서 감사합니다.
Tim Down

@ MaksimVi. : 언젠가 그게 바뀌 었는지 궁금합니다. 나는 보통 이것들을 확인합니다.
Tim Down

1
@TimDown, HTMLCollection팁 주셔서 감사합니다 . 이제 마침내 HTMLCollection.prototype.forEach = Array.prototype.forEach;내 코드에서 사용할 수 있습니다 .
Maksim Vi.

70

Array.from컬렉션을 배열로 변환 하는 데 사용할 수 있습니다 Array.prototype.forEach.call.

Array.from(document.getElementsByClassName("myclass")).forEach(
    function(element, index, array) {
        // do stuff
    }
);

을 지원하지 않는 이전 브라우저에서는 Array.fromBabel과 같은 것을 사용해야합니다.


ES6는 또한 다음 구문을 추가합니다.

[...document.getElementsByClassName("myclass")].forEach(
    (element, index, array) => {
        // do stuff
    }
);

...배열 자체는 배열 자체뿐만 아니라 모든 배열과 유사한 객체에서 작동하여 나머지 오래된 구문 구문을 사용하여 값에서 배열을 구성합니다.


대체 함수 querySelectorAll(일부 getElementsByClassName사용 하지 않음)는 forEach기본적으로 존재 map하거나 다른 메소드와 같 거나 filter누락 된 콜렉션을 리턴하지만 이 구문은 여전히 ​​유용합니다.

[...document.querySelectorAll(".myclass")].map(
    (element, index, array) => {
        // do stuff
    }
);

[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);

6
참고 : 제안 된 바에 따라 트랜스 필링 (바벨)이 없으면 IE <Edge, Opera, Safari <9, Android 브라우저, Android 용 Chrome 등에서 호환되지 않습니다 .
Sean

30

또는 NodeListquerySelectorAll 를 반환 하는 것을 사용할 수 있습니다 .

document.querySelectorAll('.myclass').forEach(...)

최신 브라우저에서 지원 (IE를 제외하고 Edge 포함) :
querySelectorAll NodeList.prototype.forEach ()를 사용할 수 있습니까

MDN : Document.querySelectorAll ()


4
마음에 베어 getElementByClassName를 통해 성능 저하
사볼 폴

3
DOM 수정과 같은 다른보다 집중적 인 작업에 비해 성능 저하가 무시할 수 있습니다. 1 밀리 초 안에 60,000 개를 실행 하면 합리적인 사용에 문제가되지 않을 것입니다. :)
icl7126

1
잘못된 벤치 마크를 연결했습니다. 다음은 올바른 thatmeasure.net/Benchmarks/Show/4076/0/… 입니다. 저급 전화기에서 실행 한 결과 160k / s vs 380k / s입니다. DOM 조작을 언급 했으므로 여기에는 thatthat.net/Benchmarks/Show/5705/0/… 도 있습니다. 50k / s vs 130k / s. 보시다시피 NodeList가 정적이기 때문에 (다른 사람들이 언급했듯이) DOM을 조작하는 것이 훨씬 느립니다. 대부분의 사용 사례에서는 여전히 무시할 수 없지만 그럼에도 불구하고 거의 3 배 느려집니다.
Szabolcs Páll

14

편집 : 새로운 버전의 HTML에서 반환 유형이 변경되었지만 (팀 다운의 업데이트 된 답변 참조) 아래 코드는 여전히 작동합니다.

다른 사람들이 말했듯이, NodeList입니다. 다음은 시도해 볼 수있는 완전하고 효과적인 예입니다.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <script>
            function findTheOddOnes()
            {
                var theOddOnes = document.getElementsByClassName("odd");
                for(var i=0; i<theOddOnes.length; i++)
                {
                    alert(theOddOnes[i].innerHTML);
                }
            }
        </script>
    </head>
    <body>
        <h1>getElementsByClassName Test</h1>
        <p class="odd">This is an odd para.</p>
        <p>This is an even para.</p>
        <p class="odd">This one is also odd.</p>
        <p>This one is not odd.</p>
        <form>
            <input type="button" value="Find the odd ones..." onclick="findTheOddOnes()">
        </form>
    </body>
</html>

이것은 Win 7의 IE 9, FF 5, Safari 5 및 Chrome 12에서 작동합니다.


9

의 결과 getElementsByClassName()는 Array가 아니라 array-like object 입니다. 구체적으로는라고 HTMLCollection혼동하지 NodeList( 갖는 그 자신의 forEach()메소드 ).

ES2015에서 Array.prototype.forEach()아직 언급되지 않은 배열과 같은 객체를 변환하는 간단한 방법 은 스프레드 연산자 또는 스프레드 구문 을 사용하는 것입니다 .

const elementsArray = document.getElementsByClassName('myclass');

[...elementsArray].forEach((element, index, array) => {
    // do something
});

2
현대 브라우저에서 이것이 올바른 방법이라고 생각합니다. 이것은 정확한 유스 케이스 스프레드 구문으로 해결되었습니다.
Matt Korostoff


3

이미 말했듯이, getElementsByClassName반환 HTMLCollection 으로 정의된다,

[Exposed=Window]
interface HTMLCollection {
  readonly attribute unsigned long length;
  getter Element? item(unsigned long index);
  getter Element? namedItem(DOMString name);
};

이전에는 일부 브라우저가 대신 NodeList 를 반환했습니다 .

[Exposed=Window]
interface NodeList {
  getter Node? item(unsigned long index);
  readonly attribute unsigned long length;
  iterable<Node>;
};

DOM4는 이제 NodeList 를 반복 가능한 것으로 정의하기 때문에 차이점이 중요합니다 .

Web IDL 초안 에 따르면

반복 가능한 것으로 선언 된 인터페이스를 구현하는 객체는 일련의 값을 얻기 위해 반복되는 지원을 제공합니다.

참고 : ECMAScript 언어 바인딩에서 반복 가능한 인터페이스인터페이스 프로토 타입 객체 에 “항목”,“forEach”,“키”,“값”및 @@ iterator 속성이 있습니다 .

즉,를 사용하려는 경우 와 같이 NodeListforEach 를 반환하는 DOM 메소드를 사용할 수 있습니다 .querySelectorAll

document.querySelectorAll(".myclass").forEach(function(element, index, array) {
  // do stuff
});

아직 널리 지원되지는 않습니다. Node.childNodes의 각 메소드를 참조하십시오 .


1
Chrome 49 반품forEach in not a function
Vitaly Zdanevich

@VitalyZdanevich Chromium 50 시험
Oriol

크롬 50에 나는 점점 오전document.querySelectorAll(...).forEach is not a function
비탈리 Zdanevich

@VitalyZdanevich Chromium 50에서 작동했지만 여전히 Chromium 53에서 작동합니다. Chrome 50으로 배송 될만큼 안정적으로 간주되지 않았을 수 있습니다.
Oriol


1

이것이 더 안전한 방법입니다.

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);

0

getElementsByClassName최신 브라우저에서 HTMLCollection 을 반환 합니다.

이는입니다 배열과 같은 인자에 유사한 물체 에 의해 iteratable입니다 for...of루프가 무엇인지 아래를 참조 MDN의 문서가 그것에 대해 말하고있다 :

에 대한 ... 반복 가능한 객체를 통해 문 루프 반복하는을 생성의 포함 : 내장 된 문자열, 배열, 배열과 같은 객체 (예를 들어, 인수 또는 NodeList를)하는 TypedArray,지도, 설정 및 사용자 정의 반복 가능 객체. 객체의 각 고유 속성 값에 대해 실행될 명령문으로 사용자 정의 반복 후크를 호출합니다.

for (let element of getElementsByClassName("classname")){
   element.style.display="none";
}

Typescript에 따르면 :error TS2488: Type 'HTMLCollectionOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.
거북이는 귀여운

@TurtlesAreCute, 여기 OP는 typescript가 아닌 javascript를 사용하고 있으며 바닐라 js 권장 사항에 따라 답변 했으므로 typescript에서는 문제에 대한 다른 해결책이 될 수 있습니다.
Haritsinh Gohil

@TurtlesAreCute, 그런데 그것은 또한 typescript에서도 작동하지만 특정 CSS 클래스의 요소를 보유하는 올바른 유형의 변수를 언급해야하므로 그에 따라 캐스팅 할 수 있습니다 . 자세한 내용은 이 답변을 참조하십시오 .
Haritsinh Gohil

0

다음은 jsperf에서 만든 테스트입니다. https://jsperf.com/vanillajs-loop-through-elements-of-class

Chrome 및 Firefox에서 가장 성능이 우수한 버전은 document.getElementsByClassName과 함께 사용하면 좋은 오래된 for 루프입니다.

var elements = document.getElementsByClassName('testClass'), elLength = elements.length;
for (var i = 0; i < elLength; i++) {
    elements.item(i).textContent = 'Tested';
};

Safari에서이 변형이 승자입니다.

var elements = document.querySelectorAll('.testClass');
elements.forEach((element) => {
    element.textContent = 'Tested';
});

모든 브라우저에서 가장 강력한 변형을 원한다면 다음과 같습니다.

var elements = document.getElementsByClassName('testClass');
Array.from(elements).map(
    (element) => {
        return element.textContent = 'Tested';
    }
);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.