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

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

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



답변

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 표준에서 제거되었습니다 .


답변

넌 할 수있어

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

    // Your code here.

} );


답변

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

  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


답변

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

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


답변

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

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에서 맵을 사용할 수 없습니까? )


답변

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

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

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

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


답변

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 확산 연산자

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