JavaScript

| JavaScript | 'DOM' 접근하기, HTMLCollection 와 NodeList

데브빈 2022. 5. 16. 01:49

DOM 이란?

: 자바 스크립트에서  웹 문서의 객체를 다루는 시스템을 '문서객체모델'(DOM)이라고 한다. 

HTML 문서의 내용을 트리형태로 구조화하여 웹페이지와 프로그래밍 언어를 연결시켜주는 역할을 한다.
이때 각각의 요소와 속성, 콘텐츠를 표현하는 단위를 '노드(node)'라고 한다.

 

👀 DOM을 왜 배워야 할까?

웹에서 js를 사용하는 이유는 웹문서의 일부를 동적으로 반응하게 하는 것인데 

이렇게 반응하게 하려면 웹 문서의 모든 요소를 따로 제어할 수 있어야한다.

또는 이미지가 몇개인지, 텍스트 몇개인지 , 어떤 조건만 해당할 것인지 제어할때 사용하는 것이 DOM이다. 

 

html 코드를 DOM으로 파싱하는 것?

  • 파싱은 어떤 데이터를 다른형태로 바꿔주는 것이다. (JS객체 > JSON객체, xml > JSON)
  • 우리가 흔히 보는 태그안에는 전부 다 노드다. 
  • 공백 텍스트 노드? HTML 요소의 스페이스, 탭 , 줄바꿈(개행) 등의 공백 문자들도 전부 노드이다.  

가장 중요한 노드 4개

1. 문서 노드

: 최상위에 존재하는 루트노드로서 document 객체를 가리킨다. (또는 window.document

DOM 트리 노드들이 접근하기 위한 진입점 역할을 한다. 

2. 요소노드

:HTML요소를 가리키는 객체 , 부자관계를 통해 정보를 구조화한다. 

3. 어트리뷰트 노드

: HTML요소의 속성을 나타내는 객체. 어트리뷰트를 참조하거나 변경시 요소노드에 먼저 접근해야한다.

4. 텍스트 노드

: HTML요소의 텍스트를 가리키는 객체. DOM트리의 최종단, 마찬가지로 참조 변경시 요소노드에 먼저 접근해야한다.


DOM 트리에 접근하기 : document 객체를 통해 HTML 문서에 접근 가능>

화면에 내용을 출력하는 document는 브라우저가 불러온 웹페이지를 나타내며, DOM 트리의 진입점 역할을 수행한다.

 

해당하는 Id를 가진 요소에 접근하기
document.getElementById()

 

해당하는 모든 요소에 접근하기
document.getElementsByTagName();

해당하는 클래스를 가진 모든 요소에 접근하기
document.getElementsByClassName();

css 선택자로 단일 요소에 접근하기 (사용한 첫번째 요소만 접근함)
document.querySelector("selector");

 css 선택자로 여러 요소에 접근하기

document.querySelectorAll("selector");

 

🗣  다 필요없고 ! 우리는 querySelector 또는 querySelectorAll 많이 쓴다.!!!?
그 이유는 좀 더 구체적인 조건과 일관적을 방식으로 요소노드를 취득할 수 있다.
또한 요소노드의 텍스트 노드, 속성노드까지 자유롭게 제어할 수 있다.
하지만 다른 메서도와 비교하여 다소 느린 것 으로 알려져 있고,
반복적인 함수 안에서 querySelector를 사용하는건 지양해야한다는 것. 바깥에서 빼서 찾아주자.
 (추가적으로  id 요소노드 취득시에는 getElementById 사용하는 것을 권장한다.) 

< HTMLCollection 와 NodeList >

 DOM API가 여러개의 결과값을 반환하기 위한 DOM 컬렉션 객체이다. 

모두 유사배열 객체이며  for ... of 문으로 순회 가능하다. 

그러나 유사 배열 객체이기 때문에 자바스크립트에서 제공하는 배열 객체의 메소드는 사용할 수 없다.(예외는 있음)

HTMLCollection

: getElementsByTagname, getElementsByClassName 메서드로 반환하여 노드 객체의 상태 변화를 실시간으로 반영하는 살아있는 live DOM 컬렉션 객체이다.  live 의미는 객체가 스스로 실시간 노드 객체의 상태 변경을 반영함을 의미한다.

하지만 forEach나, entries와 같은 편리한 메서드를 제공해주지 않는다.

    <body>
    <p class="test1">test1</p>
    <p class="test1">test1</p>

    <script type="text/javascript">
      // getElementsByClassName로 변수 만들기
      let test1 = document.getElementsByClassName("test1");

      // for반복문으로 요소 접근하기 
      for (let i = 0; i < test1.length; i++) {
        test1[i].style.color = "red";
      }

      // getElementsByClassName은 forEach를 쓰지 못한다.
      test1.forEach((i) => (i.style.color = "blue"));
      // Uncaught TypeError: test1.forEach is not a function
    </script>
    </body>

 

 

 

👉 화면 결과를 보면 forEach를 쓰지 못하기 때문에  blue 로 바뀌지않는다. 

 

 

NodeList

querySelectorAll 등의 메서드가 반환하여 노드 객체의 상태 변화를 반영하지 않는 non-live DOM 컬렉션 객체이다.  

하지만 경우에 따라 live 객체로 동작할 때가 있다.

  <body>
    <p class="test2">test2</p>
    <p class="test2">test2</p> 

    <script>

        let test2 = document.querySelectorAll('.test2');
      
        // for반복문으로 요소 접근하기 
        for(let i=0;i<test2.length;i++){
            test2[i].style.color = 'red';
        }

        // Nodelist은 forEach를 쓸 수 있다.!!
        test2.forEach(i=>i.style.color='blue')
        
        // 하지만 map은 못 쓴다.
        test2.map(i=>i.style.color='yellow')
        //Uncaught TypeError: test2.map is not a function
        
    </script>
</body>

 

 

👉 화면 결과를 보면 forEach를 쓸 수 있지만 map은 쓰지 못하기때문에  yellow 로 바뀌지않는다. 

 

 


 

 

따라서 결론은 노드 객체의 상태 변경과 상관없이 안전하게 DOM 컬렉션을 사용하려면 !!

HTMLCollection 이나 NodeList 객체를 배열로 반환하여 사용하는 것을 권장한다. 

 스프레드 문법(...) 또는 Array.form() 을 사용하여, 

간단히 배열로 변환해서 배열의 메서드 (고차함수: forEach,map,filter,reduce 등) 맘껏 쓸 수 있다~! 

 

 

 

[참고]

모던 js DeepDive 

혼자공부하는js

https://basemenks.tistory.com/46