FE/JavaScript

[JS] DOM (1) - DOM이란?

mandelina 2022. 5. 17. 18:09

DOM이란?

- HTML 문서의 계층적 구조와 정보를 표현하며, 이를 제어할 수 있는 API (프로퍼티,메소드)를 제공하는 트리자료구조이다. 

 

- 이때 각각의 요소와 속성, 콘텐츠를 표현하는 단위를 "노드 (node)" 라고 한다.

 

여기서 나오는 트리자료구조에 대해 잠깐 알아보자.

 

 

Tree Data Structure?

- 트리자료구조는 노트들의 계층구조로 이뤄진다.

- 부모,자식노드로 구성되어 노드간 계층적 구조를 표현하는 비선형 자료구조이다.

- 최상위 노드는 root노드라고하고, 자식노드가 없는 노드를 leaf노드라고 한다.

 

 


노드타입?

노드타입은 총 12개지만 중요한 노트 타입 4가지를 살펴보자.

 

1. 문서노드

- DOM 트리의 최상위에 존재하는 루트노드 -> 노드들의 진입점역할

- document 객체를 가리킴

- 문서당 document 객체는 유일

- window.document 또는 document로 참조가능 

- document ?  HTML 문서 전체를 가리키는 객체

                    전역 객체의 window의 document 프로퍼티에 바인딩 되어있다. 

 

 

 

2. 요소노드

- HTML을 가리키는 객체

- HTML 요소간 중첩에 의해 부자관계를 가짐

- 문서의 구조를 표현

 

3. 어트리뷰트 노드

- HTML요소의 어트리뷰트를 가리킴

- 어트리뷰트가 지정된 HTML 요소의 요소노드와 연결되어 있음

- 어트리뷰트 노드는 부모노드가 없으므로 요소노드의 형제노드는 아님

- 어트리뷰트 노드를 통해 참조,변경하려면 먼저 요소노드에 접근해야함.

 

 

4. 텍스트노드 

- HTML요소의 텍스트를 가리킴

- 요소노드의 자식노드, 자식을 가질수없는 leaf노드

- DOM 트리의 최종단

- 텍스트노드에 접근하려면 먼저 부모노드인 요소노드에 접근해야함.

 


 

그밖에 Comment노드(주석) , DocumentType노드 (DOCTYPE) , Document Fragment노드 (복수노드 추가 및 생성) 의 12개 노트타입이 있다. 


요소노드취득

 

HTML의 구조나 내용,스타일을 동적으로 조작하기 위해선 제일먼저 요소노드를 취득해야한다.

그 방법엔 크게 4가지가 있다. 

 

1) ID를 통해 요소노드 취득

 

const element = document.getElementById('id값')

- 중복된 ID 값을 갖는 요소가 여러개 존재할 경우, 첫 번째 요소만 반환한다.

- getElementById 메서드는 언제나 단 하나의 요소노드를 반환한다.

- 만약 id 값을 가진 HTML요소가 존재하지 않으면 null을 반환한다.

 


 

2) 태그 이름을 이용한 요소노드 취득

 

document.getElementsByTagName('태그이름');

//만약 모든 요소 노드를 취득하려면 
document.getElementsByTagName('*');

- 인수로 전달한 태그 이름을 갖는 모든 요소 노드들을 탐색하여 반환한다. 

- 여러개의 요소 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.

 

 


3) class를 이용한 요소노드취득

document.getElementsByClassName('클래스 이름');

- class 어트리뷰트 값을 갖는 모든 요소 노드들을 탐색하여 반환한다.

- 여러개의 요소 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.

 


 

4) css 선택자를 이용한 요소노드 취득

document.querySelector("selector");

- 단일요소에 접근한다.

 

 

document.querySelectorAll("selector");

- 여러 요소에 접근한다.

 


 

5) 특정 요소 노드를 취득할 수 있는지 확인

const apple = document.querySelector('.apple');
apple.matches('#fruit > li.apple')  //matches 메서드 사용

- Element.prototype.matches 메서드를 통해 특정 요소 노드를 취득할 수있는지 확인한다.

- 반환값은 boolean이다.

 

 

 


HTMLCollection & NodeList

 

- DOM 컬렉션 객체이다

- 유사배열 객체이며 이터러블하다.

- for ... of 문으로 순회 가능하다. 

- 노드 상태변화를 실시간으로 반영하는 live 객체이다.

 

 

하지만 for문을 사용해 순회하며 className을 바꿀시 예상치 못한 결과가 나올 수 있다.

 

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HTMLCollection 오류</title>
  </head>
  <style>
    .red {
      color: red;
    }
    .blue {
      color: blue;
    }
  </style>
  <body>
    <ul class="color">
      <li class="red">one</li>
      <li class="red">two</li>
      <li class="red">three</li>
    </ul>
  </body>
  <script>
    const color = document.getElementsByClassName("red");
    for (let i = 0; i < color.length; i++) {
      color[i].className = "blue";
    }
    console.log(color);
  </script>
</html>

 

위의 코드로 li의 className을 blue로 바꿔본다고 하자.

for문으로 순회하며 잘 돌아가 결과는 모두 파란색으로 나올것 같지만 실제는. . . 

 

2번째 경우 빨간색인것을 알 수 있다. 

 

Q. 왜 이런 결과가 나올까?

A. HTMLCollection live 객체이기 때문에 실시간으로 li요소를 제거하며 순회를 돌다보니 오류가 발생하는 것이다.

 


 

 

- 이 경우 for문을 역방향 순회하거나, HTMLCollection객체에 노드 객체가 남아 있지 않을때 까지 무한방법으로 문제를 회피할 수 있지만 가장 좋은 해결책은 HTMLCollection을 사용하지 않는것이다.

 

 

 

- 이런 부작용을 해결하기 위해 querySelectorAll 메서드를 사용하는 방법이 있다.

querySelectorAllNodeList 객체를 반환하는데, 이 객체는 non-live 객체이기 때문이다. 

 

 

 

- 하지만 childNodes 프로퍼티가 반환하는 NodeList 객체live 객체이므로 주의가 필요하다.

 

 

for(let i = 0; i< childNode.length ; i++){
	fruit.removeChild(childNodes[i]);   //live객체로 동작한다.
}

 

 


 

 

- 노드 객체의 상태변경과 상관없이 안전하게 DOM 컬렉션을 사용하려면 HTMLCollection이나 NodeList를 배열로 변환하여 사용하자!!
(예상과 다르게 동작할때도 있고, 고차함수도 사용하지 못하기 때문)

- HTMLCollection이나 NodeList는 유사배열객체이며 이터러블하기때문에 스프레드 문법이나, Array.from 메서드를 사용하여 간단히 배열로 변환할 수 있다. 

 

 

 

* 모던 자바스크립트 DeepDive를 참고하였습니다.

 

 

 

https://mandelina-code.tistory.com/58

 

[JS] DOM (1) - DOM이란?

DOM이란? - HTML 문서의 계층적 구조와 정보를 표현하며, 이를 제어할 수 있는 API (프로퍼티,메소드)를 제공하는 트리자료구조이다. - 이때 각각의 요소와 속성, 콘텐츠를 표현하는 단위를 "노드 (nod

mandelina-code.tistory.com

https://mandelina-code.tistory.com/59

 

[JS] DOM (2) - 노드 탐색 , 및 Text 조작

노드탐색 - 요소노드를 얻고, DOM트리의 노드를 옮겨다니며 탐색할 경우가 있다. - 노드탐색 프로퍼티는 모두 자체적으로 값을 갖진 않고 다른 데이터 프로퍼티 값을 읽거나 저장할 때 호출되는

mandelina-code.tistory.com

https://mandelina-code.tistory.com/62

 

[JS] DOM (3) - DOM 조작

DOM 조작 - DOM조작이란 새로운 노드를 생성하여 DOM에 추가하거나, 기존 노드를 삭제 또는 교체하는것을 말한다. - 성능에 영향을 주므로 최적화를 위해 주의하여 다뤄야한다. innerHTML - 요소

mandelina-code.tistory.com

https://mandelina-code.tistory.com/66

 

DOM(4) - attribute 조작 및 style조작

 Attribute? - HTML 요소의 동작을 제어하기 위한 추가적인 정보를 제공한다. - 글로벌 어트리뷰트 :id , class ,style ,title ,lang ,hidden 등 - HTML 문서가 파싱될때 , 어트리뷰트 하나당 하나의 노드가 생성..

mandelina-code.tistory.com

 

'FE > JavaScript' 카테고리의 다른 글

[JS] DOM (3) - DOM 조작  (0) 2022.05.18
[JS] DOM (2) - 노드 탐색 , 및 Text 조작  (0) 2022.05.18
[JS] JSON  (0) 2022.05.16
[JS] Prototype  (0) 2022.05.16
[JS] DOM - Event Flow  (0) 2022.05.12