Javascript

[javascript] nodeList와 HTMLCollection의 차이 (children과 childNodes의 차이)

tea-tea 2024. 10. 14. 10:03

dom의 프로퍼티인 children와 childNodes.

그리고 nodeList와 HTMLCollection는 

겉으로 보기에는 둘 다 dom 배열을 반환하지만, 다음 차이가 있다.

  • html 노드만 반환하는가
  • 어떻게 배열 요소에 접근가능한가
  • 동적인가 정적인가

1. html 노드만 반환하는가


nodeList는 dom 외에 text 노드와 주석 노드를 가질 수 있다.

HTMLCollection은 dom 만 요소로 가질 수 있다.

 

그러면 어떤 경우에 nodeList는 dom 이외의 노드를 가질까.

nodeList를 반환받는 방법은 크게 두 가지이다.

  • element.querySelectorAll() 의 반환값
  • node.childNodes의 반환값

이 중에서 querySelectorAll은 dom 노드로만 이뤄진 배열을 반환하고, 

childNodes는 dom와 text 노드, 주석 노드까지 반환한다.

 

element.children으로 접근한 HTMLCollection은 직접 자식요소인 dom 노드로만 이뤄진 배열을 반환한다.

예시

아래 예시 html과 연결된 javascript 파일 app2.js에서는 ul.ul1 태그의 직접 자식 요소를 querySelectorAll, childNodes, children으로 참조하여 출력한다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <ul class="ul1">
      <!-- 주석1 -->
      <li name="el1" id="el-id1" class="el-class1">요소1</li>
      텍스트1
      <li name="el2" id="el-id2" class="el-class2">요소2</li>
      텍스트2
      <li name="el3" id="el-id3" class="el-class3">요소3</li>
      <!-- 주석2 -->
    </ul>
    <div></div>
    <div>
      <button class="list-add">리스트 추가</button>
      <button class="list-remove">리스트 삭제</button>
    </div>
  </body>
  <script src="./app2.js"></script>
</html>
const ul1 = document.querySelector(".ul1");
const nodeListQuerySelectorAll = document.querySelectorAll(".ul1 > *");
const nodeListChildNodes = ul1.childNodes;
const children = ul1.children;

const consoleChildNodesChildren = function () {
  console.log("nodeListQuerySelectorAll", nodeListQuerySelectorAll);
  console.log("nodeListChildNodes", nodeListChildNodes);
  console.log("children", children);
};

consoleChildNodesChildren();

 

결과는 다음과 같다.

// QuerySelectorAll 
// dom 노드만
nodeListQuerySelectorAll 
NodeList(3) [li#el-id1.el-class1, li#el-id2.el-class2, li#el-id3.el-class3]

// ChildNodes
// dom 노드, text노드, 주석 노드
nodeListChildNodes
NodeList(11) [text, comment, text, li#el-id1.el-class1, text, li#el-id2.el-class2, 
text, li#el-id3.el-class3, text, comment, text]

// children
// dom 노드만
children
HTMLCollection(3)
[li#el-id1.el-class1, li#el-id2.el-class2, li#el-id3.el-class3,
el-id1: li#el-id1.el-class1, el1: li#el-id1.el-class1, el-id2: li#el-id2.el-class2,
el2: li#el-id2.el-class2, el-id3: li#el-id3.el-class3, …]

 

2. 동적인가 정적인가


NodeList와 HTMLCollection은 경우에 따라 해당 dom의 변화를 동적으로 반영하거나 반영하지 않는다.

 

NodeList

queryselectorAll로 얻는  NodeList는 dom 배열의 변화를 동적으로 반영하지 않는다.

childNodes로 얻는  NodeList는 dom 배열의 변화를 동적으로 반영한다.

 

HTMLCollection

children으로 얻은 HTMLCollection은 dom 배열의 변화를 동적으로 반영한다.

 

예시

아까 전의 html과 연결된 새 javascript 파일 app2.js에서는 "리스트 추가" 버튼과 "리스트 삭제" 버튼을 클릭 시, 각각 새로운 li를 추가하거나 삭제한다.

추가 혹은  삭제 후 이벤트 실행 전에 변수에 저장했던 ul.ul1 태그의 queryselectorAll, childNodes, children을 출력한다.

 

const ul1 = document.querySelector(".ul1");
const nodeListQuerySelectorAll = document.querySelectorAll(".ul1 > *");
const nodeListChildNodes = ul1.childNodes;
const children = ul1.children;

const consoleChildNodesChildren = function () {
  console.log("nodeListQuerySelectorAll", nodeListQuerySelectorAll);
  console.log("nodeListChildNodes", nodeListChildNodes);
  console.log("children", children);
};

consoleChildNodesChildren();

const btnAdd = document.querySelector(".list-add");
const btnRemove = document.querySelector(".list-remove");

// 리스트 추가 후 콘솔 출력
function addList() {
  const li = document.createElement("li");
  li.innerText = "추가 li";
  ul1.appendChild(li);
  consoleChildNodesChildren();
}

// 리스트 삭제 후 콘솔 출력
function removeList() {
  ul1.children[ul1.children.length - 1].remove();
  consoleChildNodesChildren();
}

btnAdd.addEventListener("click", addList);
btnRemove.addEventListener("click", removeList);

 

결과는 리스트를 추가하거나 삭제할 때 마다 childNodes으로 얻은 NodeList와 children으로 얻은 HTMLCollection은 lenth가 변경된다.

 

3. 어떻게 배열 요소에 접근가능한가


nodeList는 유사 배열 객체로서 일반적인 배열처럼 대괄호 접근자와 인덱스로 접근가능하다.

HTMLCollection도 동일한 유사 배열 객체이고 대괄호 접근자에 인덱스로 접근가능하지만, html의 id, name으로도 접근가능하다. 

 

예시

아까의 html에 다음 자바스크립트 코드를 이용하여 HTMLCollection의 첫번째 자식 요소에 접근해본다.

배열의 인덱스는 물론이고, id, name으로도 대괄호 접근자로 접근가능하다.

class는 되지 않는다.

const ul1 = document.querySelector(".ul1");
const nodeListQuerySelectorAll = document.querySelectorAll(".ul1 > *");
const nodeListChildNodes = ul1.childNodes;
const children = ul1.children;

console.log("HTMLCollection의 첫번째 자식에 접근하기");
console.log("자식 요소의 index로 접근 : children[0]", children[0]);
console.log("자식 요소의 id로 접근 : children['el-id1']", children["el-id1"]);
console.log("자식 요소의 name으로 접근: children['el1']", children["el1"]);

// 이건 안됨
console.log(
  "자식 요소의 class로 접근 : children['el-class1']",
  children["el-class1"]
);