이벤트 핸들러 함수에서 어떠한 DOM 요소의 자식 요소들에 접근하기 위해서 .children 을 사용합니다.

const parentElement = document.querySelector('.parent');
console.log(parentElement.children)

parentElement.children.forEach(function (entry) {
  console.log(entry);
});

위에서 작성한 코드에서 parentElement.children 은 자식 DOM 요소들이 담긴 리스트를 반환하기 때문에, 당연히 배열의 forEach 메소드를 사용하여 각각의 요소에 접근하여 어떤 동작을 수행할 수 있을 것이라고 생각하였습니다.

하지만 다음과 같은 에러 메세지를 콘솔 창에 빨간 글씨로 출력합니다.

TypeError: document.querySelector('.parent').children.forEach is not a function

 

그 이유는, .children 속성은 배열이 아닌 HTML Collection을 값으로 가지고 있습니다. HTML Collection은 length 속성을 가지고 있는 배열처럼 생긴 객체입니다. 하지만 Array.prototype으로부터 상속받지 않기 때문에 배열이 아닙니다.

그렇더라도, forEach 메소드를 사용할 방법은 있습니다. 바로 HTML Collection을 배열로 변환해주는 것입니다.

// ES6 이전의 문법
const children = [].slice.call(document.getElementById(...).children);

// ES6 문법
const children = Array.from(document.getElementById(...).children);

// ES6 문법2
const children = [...document.getElementById(...).children];
[...document.getElementById(...).children].forEach(child => console.log(child));

이렇게 배열로 변환된 children 은 이제부터 forEach 메소드 사용이 가능합니다.

 

이외에도, 다른 방법을 발견하였는데 되도록 이 방법은 권장하지 않습니다.

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

document.getElementById("niceParent").children.forEach(...)

위의 코드에서는 forEach가 이미 존재하더라도 무조건 각 prototype에 추가하고 있습니다. 따라서 비효율적인 코드입니다. 더 좋은 방법은 실제로 forEach 메소드가 prototype에 존재하지 않은 경우에만 추가하는 것입니다.

if (window.NodeList && !NodeList.prototype.forEach) {
   NodeList.prototype.forEach = Array.prototype.forEach;
}
if (window.HTMLCollection && !HTMLCollection.prototype.forEach) {
   HTMLCollection.prototype.forEach = Array.prototype.forEach;
}

 

출처 : 스택오버플로우 질문 : Why is forEach not working for children?

복사했습니다!