노드 목록에 forEach가없는 이유는 무엇입니까?


91

<abbr>요소의 내부 텍스트 를 변경하기 위해 짧은 스크립트를 작업 중이 었지만 메서드 nodelist가없는 것으로 나타났습니다 forEach. 나는 그것이 nodelist에서 상속하지 않는다는 것을 알고 Array있지만 forEach유용한 방법 이 아닌 것 같 습니까? 추가 forEach할 수없는 특정 구현 문제 가 nodelist있습니까?

참고 : Dojo와 jQuery는 모두 forEach노드 목록에 대해 어떤 형태로든 있다는 것을 알고 있습니다. 제한으로 인해 사용할 수 없습니다.


6
안녕하세요! nodeList에는 ES6 이후 forEach가 있습니다.
Blaise

답변:


94

NodeList는 이제 모든 주요 브라우저에서 forEach ()를 갖습니다.

MDN의 nodeList forEach ()를 참조하십시오 .

원래 답변

이 답변 중 어떤 것도 NodeList가 Array에서 상속하지 않는 이유를 설명 하지 않으므로 forEach나머지 는 모두 가질 수 있습니다 .

대답은 이 es-discuss 스레드 에서 찾을 수 있습니다. 요컨대, 웹을 깨뜨립니다.

문제는 instanceof가 인스턴스가 Array.prototype.concat과 결합 된 Array임을 의미하는 것으로 잘못 가정 한 코드였습니다.

Google의 Closure Library에 버그가있어서 거의 모든 Google 앱이 이로 인해 실패했습니다. 라이브러리는 이것이 발견 되 자마자 업데이트되었지만 concat과 함께 동일한 잘못된 가정을하는 코드가 여전히있을 수 있습니다.

즉, 일부 코드는 다음과 같은 작업을 수행했습니다.

if (x instanceof Array) {
  otherArray.concat(x);
} else {
  doSomethingElseWith(x);
}

그러나 concat"실제"배열 (배열의 인스턴스가 아님)을 다른 객체와 다르게 취급합니다.

[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat(4) // [1, 2, 3, 4]

즉, 위의 코드 x는 NodeList 일 때 깨 졌다는 것을 의미합니다. 왜냐하면 그것이 doSomethingElseWith(x)경로를 따라 내려 가기 전에는 경로를 따라 내려 갔고 실제 배열이 아니기 otherArray.concat(x)때문에 이상한 일을했기 때문 x입니다.

한동안 ElementsArray의 실제 하위 클래스이고 "새 NodeList"로 사용될 클래스 에 대한 제안이있었습니다 . 그러나 다양한 기술 및 사양 관련 이유로 아직 구현할 수 없었기 때문에 적어도 지금 은 DOM 표준에서 제거되었습니다 .


11
나에게 나쁜 전화 인 것 같습니다. 진지하게, 특히 미래에 대한 정상적인 API가 있다는 것을 의미하는 경우 가끔씩 문제를 해결하는 올바른 결정이라고 생각합니다. 게다가,이 아니 웹 가까운 안정적인 플랫폼 인 심지어처럼, 사람들은 자신의 2 살 자바 스크립트가 더 이상 예상대로 작동하는 데 사용됩니다 ..
JoyalToTheWorld

3
"휴식 웹"= "휴식 구글의 물건을!"
매트

왜 Array.prototype에서 forEach 메서드를 빌려주지 않습니까? 예를 들어 Array를 프로토 타입으로 추가하는 대신 생성자에서 this.forEach = Array.prototype.forEach를 수행하거나 NodeList에 대해 고유하게 forEach를 구현할 수 있습니까?
PopKernel 2018

1
노트; 이 업데이트 NodeList now has forEach() in all major browsers는 IE가 주요 브라우저가 아님을 암시하는 것 같습니다. 바라건대 그것은 어떤 사람들에게는 사실이지만 나에게는 사실이 아닙니다 (아직).
Graham P Heath

58

넌 할 수있어

Array.prototype.forEach.call (nodeList, function (node) {

    // Your code here.

} );

3
Array.prototype.forEach.call[].forEach.call
단축

7
@CodeBrauer : 그것은 단지 단축하는 것이 아니라 Array.prototype.forEach.call빈 배열을 만들고 그 forEach방법을 사용하는 것입니다.
Paul D. Waite

34

새로운 노드 배열 생성을 고려할 수 있습니다.

  var nodeList = document.getElementsByTagName('div'),

      nodes = Array.prototype.slice.call(nodeList,0); 

  // nodes is an array now.
  nodes.forEach(function(node){ 

       // do your stuff here.  

  });

참고 : 이것은 우리가 여기서 만들고있는 노드 참조의 목록 / 배열 일 뿐이며 중복 노드는 없습니다.

  nodes[0] === nodeList[0] // will be true

22
아니면 그냥하세요 Array.prototype.forEach.call(nodeList, fun).
akuhn 2014 년

또한 forEach 함수를 다음과 같이 별칭으로 지정하는 것이 좋습니다 var forEach = Array.prototype.forEach.call(nodeList, callback);. 지금 당신은 간단하게 호출 할 수 있습니다forEach(nodeList, callback);
앤드류 Craswell에게

19

결코 말하지 마십시오. 2016 년이고 NodeList객체는 forEach최신 크롬 (v52.0.2743.116)에서 메서드를 구현했습니다 .

다른 브라우저가 아직이를 지원하지 않기 때문에 프로덕션에서 사용하기에는 너무 이르지만 (테스트 된 FF 49) 조만간 표준화 될 것이라고 생각합니다.


2
Opera는 또한이를 지원하며 15/11/16에 출시 될 예정인 Firefox v50에 지원이 추가 될 예정입니다.
Shaggy 2011

1
구현되었지만 표준의 일부가 아닙니다. Array.prototype.slice.call(nodelist).forEach(…)표준이고 오래된 브라우저에서 작동하는 것이 가장 좋습니다 .
Nate

17

요컨대, 그 방법을 구현하는 것은 디자인 충돌입니다.

MDN에서 :

NodeList에서 forEach 또는 map을 사용할 수없는 이유는 무엇입니까?

NodeList는 배열과 매우 유사하게 사용되며 Array.prototype 메소드를 사용하고 싶을 것입니다. 그러나 이것은 불가능합니다.

JavaScript에는 프로토 타입을 기반으로하는 상속 메커니즘이 있습니다. 배열 인스턴스는 프로토 타입 체인이 다음과 같기 때문에 배열 메서드 (예 : forEach 또는 map)를 상속합니다.

myArray --> Array.prototype --> Object.prototype --> null (객체의 프로토 타입 체인은 Object.getPrototypeOf를 여러 번 호출하여 얻을 수 있습니다.)

forEach, map 및 like는 Array.prototype 객체의 고유 속성입니다.

배열과 달리 NodeList 프로토 타입 체인은 다음과 같습니다.

myNodeList --> NodeList.prototype --> Object.prototype --> null

NodeList.prototype에는 항목 메서드가 포함되어 있지만 Array.prototype 메서드는 없으므로 NodeList에서 사용할 수 없습니다.

출처 : https://developer.mozilla.org/en-US/docs/DOM/NodeList ( 왜 forEach를 사용할 수 없거나 NodeList에서 맵을 사용할 수 없습니까? )


8
그렇다면 목록이기 때문에 왜 그렇게 설계 되었습니까? 그들이 사슬을 만드는 것을 막는 것은 무엇입니까 myNodeList --> NodeList.prototype --> Array.prototype --> Object.prototype --> null?
Igor Pantović 2014 년

14

NodeList에서 forEach를 사용하려면 Array에서 해당 함수를 복사하십시오.

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

그게 전부입니다. 이제 Array와 동일한 방식으로 사용할 수 있습니다.

document.querySelectorAll('td').forEach(function(o){
   o.innerHTML = 'text';
});

4
기본 클래스를 변경하는 것은 일반 독자에게 그다지 명시 적이 지 않다는 점을 제외하면. 즉, 일부 코드에서 브라우저 기본 개체에 대한 모든 사용자 지정을 기억해야합니다. MDN 문서에 의존하는 것은 객체가 표준에서 동작을 변경했기 때문에 더 이상 유용하지 않습니다. 독자가 forEach가 언어 정의의 일부가 아니라 빌린 아이디어라는 것을 쉽게 알 수 있도록 호출시 프로토 타입을 명시 적으로 적용하는 것이 좋습니다. @akuhn이 위의 답변을 참조하십시오.
Sukima 2015 년

@Sukima는 잘못된 전제에 의해 오도되었습니다. 이 특정 경우에 주어진 접근 방식은 NodeList가 개발자가 예상 한대로 동작하도록 수정합니다. 이것은 시스템 클래스 문제를 해결하는 가장 적절한 방법입니다. (NodeList는 미완성 된 것으로 보이며 향후 언어 버전에서 수정되어야합니다.)
Daniel

1
이제 NodeList.forEach가 존재하므로 이것은 매우 단순한 폴리 필이됩니다!
Damon

7

ES2015에서는 이제 forEachnodeList에 메소드를 사용할 수 있습니다 .

document.querySelectorAll('abbr').forEach( el => console.log(el));

참고 항목 MDN 링크

그러나 HTML 컬렉션 또는 기타 배열과 유사한 객체를 사용하려는 경우 es2015에서 Array.from()메서드 를 사용할 수 있습니다 . 이 메서드는 배열과 유사하거나 반복 가능한 객체 (nodeList, HTML 컬렉션, 문자열 등 포함)를 취하고 새 Array 인스턴스를 반환합니다. 다음과 같이 사용할 수 있습니다.

const elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( el => console.log(el));

으로 Array.from()방법은 shimmable, 당신은이 같은 ES5 코드에서 사용할 수 있습니다

var elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( function(el) {
    console.log(el);
});

자세한 내용은 MDN 페이지를 참조하십시오.

현재 브라우저 지원 을 확인하려면 .

또는

또 다른 es2015 방법은 스프레드 연산자를 사용하는 것입니다.

[...document.querySelectorAll('abbr')].forEach( el => console.log(el));

MDN 확산 연산자

스프레드 연산자-브라우저 지원


2

내 솔루션 :

//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;

1
특히 이전 버전의 IE에서 프로토 타입을 통해 DOM의 기능을 확장하는 것은 좋은 생각이 아닙니다 ( article ).
KFE

0

NodeList는 DOM API의 일부입니다. JavaScript에도 적용되는 ECMAScript 바인딩을 살펴보십시오. http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html . nodeList 및 읽기 전용 길이 속성과 node를 반환하는 item (index) 함수.

대답은 반복해야한다는 것입니다. 대안이 없습니다. Foreach는 작동하지 않습니다. Java DOM API 바인딩으로 작업하고 동일한 문제가 있습니다.


그러나이를 구현해서는 안되는 특별한 이유가 있습니까? jQuery와 Dojo 모두 자체 라이브러리에서 구현했습니다
Snakes and Coffee

2
그러나 그것은 어떻게 디자인 충돌입니까?
Snakes and Coffee

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.