본문 바로가기

Web/Javascript

[JAVASCRIPT] DOM - 노드 취득 (HTMLCollection)

노드 취득

  • 프론트엔드 개발자의 관점에서 HTML 태그 는 단순 태그를 넘어서 자바스크립트 객체의 관점으로 보아야 한다.
  • DOM 에 접근할 수 있는 DOM API의 종류
API 설명
getElementById 태그의 id 속성을 이용하여 노드를 선택한다.
getElementsByClassName 태그의 class 속성을 이용하여 노드를 선택한다. HTMLCollection 유사 배열객체 를 리턴
getElementsByTagName 태그의 이름을 이용하여 노드를 선택한다. HTMLCollection 유사 배열객체 를 리턴
querySelector CSS 선택자를 사용하여 노드를 선택한다. 
querySelectorAll CSS 선택자를 사용하여 여러 노드를 선택한다. NodeList 유사 배열객체를 리턴

getElementById

document.getElementById( id );
  • id 값을 이용하여 노드를 선택한다.
  • 같은 id 를 갖는 여러 태그가 있을경우 첫 번째 노드만 반환하고, id 값을 가진 태그가 없는 경우 null 을 리턴한다.
  • id 값과 동일한 이름의 전역변수가 암묵적으로 선언되고 동일한 이름의 전역변수가 존재할 경우 노드 객채가 할당되지 않는다.
  <body>
    <ul>
      <li id="red">red</li>
      <li id="blue">blue</li>
    </ul>
    <script>
      const $red = document.getElementById("red");
      const $blue = document.getElementById("blue");
      console.log($red); // li#red
      console.log($blue); // li#blue
    </script>
  </body>

getElementsByClassName

document.getElementsByClassName( class );
  • class 를 사용하여 노드를 선택한다.
  • HTMLCollection 는 여러 노드 객체를 가지고 있는 유사 배열 객체를 리턴한다.
 <body>
    <ul>
      <li class="list">red</li>
      <li class="list">blue</li>
    </ul>
    <script>
      const $lists = document.getElementsByClassName("list");
      console.log($lists); // HTMLCollection(2) [li.list, li.list]
    </script>
  </body>

getElementsByTagName

document.getElementsByTagName( div )
  • tag 이름을 기준으로 노드를 선택한다.
  <body>
    <ul>
      <li class="list">red</li>
      <li class="list">blue</li>
    </ul>
    <script>
      const $li = document.getElementsByTagName("li");
      console.log($lis); // HTMLCollection(2) [li.list, li.list]
    </script>
  </body>

querySelector & querySelectorAll 

document.querySelector( );
document.querySelectorAll( );
  • CSS 의 선택자 방식을 사용해서 노드를 선택하는 방법으로 복잡하거나 정교한 노드 선택 이 가능하다.
  • querySelectorAll 을 사용하여 노드를 선택할경우 NodeList 라는 유사 배열 객체를 리턴한다.
  • 기존의 태그 아이디, 클래스 의 이름을 찾아 노드를 선택하는 메소드보다 querySelector 가 속도면에선 느리다.
  <body>
    <div id="user" class="box">
      <p class="name">이름 : 혜성</p>
      <p class="age">나이 : 27</p>
      <input type="text" />
    </div>
    <script>
      const $user = document.querySelector("#user"); // div#user.box
      const $box = document.querySelector(".box"); // div#user.box
      const $p = document.querySelectorAll("p"); // NodeList(2) [p.name, p.age]
      const $name = document.querySelector("#user > .name"); // p.name
      const $age = document.querySelector(".box > .age"); // p.age
      const $input = document.querySelector("input[type='text']"); // <input type="text">
    </script>
  </body>

 


HTMLCollection, NodeList 🔥

getElementsByClassName 를 사용했을때 리턴하는 HTMLCollection 객체와 querySelector 가 리턴하는 NodeList 객체모두 배열이아닌 유사 배열 객체이다.

 

두 객체의 특징은 ( live ) 상태를 실시간으로 반영한다. 

NodeList 는 대부분 non-live 형태로 동작하나 일부는 live 한 상태로 존재한다.

그렇다면 이 살아있다는 상태, 실시간으로 상태변화를 감지한다는것은 무슨 의미를 갖는가?

  <head>
    <style>
      .red {
        color: red;
      }
      .blue {
        color: blue;
      }
    </style>
  </head>
  <body>
    <ul>
      <li class="red">a</li>
      <li class="red">b</li>
      <li class="red">c</li>
    </ul>
    <script>
      const $elem = document.getElementsByClassName("red");
      for (let i = 0; i < $elem.length; i++) {
        $elem[i].className = "blue";
      }
    </script>
  </body>
</html>

 

위의 코드의 결과 값은 아래 이미지와 같다.

결과를 기대하기에 모든 li 태그는 blue 로 변경되길 원했으나 동작이 이상하게 작동했다.

 

이유는 HTMLCollection가 실시간으로 감지하여 첫번째 노드의 클래스를 blue 변경 한 순간 $elem.length 의 길이가 2로 변했고,

두번째 순회 상태일때 ( i = 1 일때 ) 3번째 변경되길 원했던 li 노드가 먼저 변경되어버린다.

 

따라서 HTMLCollection 바로 순회에 사용하는 것에는 주의가 필요하다.

이러한 부작용을 제거하기 위해선 해당 유사 배열 객체들을 배열 객체로 변환하여 사용한다.

 

[...$elem].forEach(elem => elem.className = "blue"); // 첫번째 방법
Array.from($elem).forEach(elem => elem.className = "blue"); // 두번째 방법

Reference

  • 모던 자바스크립트 (이웅모)

There might be incorrect information or outdated content.

'Web > Javascript' 카테고리의 다른 글

[JAVASCRIPT] DOM - 노드 조작  (0) 2023.08.04
[JAVASCRIPT] DOM - 노드 탐색  (0) 2023.08.04
[JAVASCRIPT] Full Screen  (0) 2023.07.29
[JAVASCRIPT] STRING  (0) 2023.07.29
[JAVASCRIPT] ARRAY  (0) 2023.07.28