[JS] DOM이란?

_sqrlkoo·2023년 12월 18일
0
post-thumbnail

사내 프로젝트를 진행하면서 document 메서드를 다루던 중 에러를 발견했는데 그 에러가 왜 일어났는지 이해가 어려웠다. 그래서 퇴근 후에 DOM을 다루는 메서드를 집중적으로 공부해야겠다는 생각이 들었다.

오늘 DOM에 대해 다시 공부하니 그동안 내가 제대로 이해하고 사용한 것이 아니라는 것을 깨달았다. 그래서 마지막으로 DOM을 좀 더 심도 있게 다뤄 정리할 예정이다.

나도 주니어 개발자로서 이해가 어려웠던 부분을 구체적으로 작성하려고 노력했다. DOM을 아예 처음 학습하는 개발자라도 이 글을 천천히 읽다보면 어느정도 DOM을 이해할 수 있을 것이라고 생각한다.

DOM

브라우저의 렌더링 엔진은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 자료 구조인 DOM을 생성한다.

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

나는 처음 DOM을 공부할 때 정의를 보고 이해가 가지 않았던 기억이 있다.

프로퍼티는 무엇이고 메서드는 무엇인가.. 처음부터 어려운 용어의 연속이지만
중요한건 DOM은 HTML 문서를 파싱(분석)하여 만들어진 결과물이다.

그리고 DOM은 HTML 문서의 구조, 정보를 표현하고 그 표현 방법이 트리 자료 구조라는 것이다.

Node

HTML 요소는 HTML 문서를 구성하는 개별적인 요소를 의미한다.
요소의 구조는 다음과 같습니다.

요소의 예시!

<div class="greeting">Hello</div>

요소에 해당하는 부분들에 대한 정의

// div -> tag
// class -> attribute name
// greeting -> attribute value
// Hello -> content

HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다. 이때 HTML요소의 어트리뷰트는 어트리뷰트 노드로, 텍스트 콘텐츠는 텍스트 노드로 변환된다.

DOM을 구성하는 요소 노드 객체로 변환된다.

💡 그럼 여기서 객체란 무엇인가?

DOM에서의 "객체"는 프로그래밍에 사용되는 일종의 추상화된 개념으로, 실제로는 JavaScript 객체와 완전히 동일하지 않다. 하지만 DOM을 통해 문서를 다룰 때, 이러한 노드들을 객체처럼 취급하여 접근하고 조작할 수 있다.

결국, DOM에서 말하는 객체는 어떤 요소를 일컫는 것 뿐이지 {} 이런 모양의 객체는 아니라는 것이다.

다시 설명으로 돌아와서 HTML 문서는 HTML 요소들의 집합으로 이루어지며, HTML요소는 중접 관계를 갖는다.

중첩 관계라고 하는 것은 이런 것이다.

- Document
  - html
    - head
      - title
        - text: "Sample Document"
    - body
      - h1
        - text: "Hello, World!"
      - p
        - text: "This is a sample paragraph."
        
 // htlm 안에 body, head가 포함되어 있고, body에 h1, p 태그가 포함되어 있다.

HTML 요소간의 컨텐츠 영역에는 텍스트, 그리고 다른 HTML 요소도 포함할 수 있다.

<div>
	텍스트도 들어갈 수 있고
	<p>요소도 들어갈 수 있습니다.</p>
    <p></p>
</div>

트리 자료구조

트리 자료구조는 노드들의 계층 구조로 이뤄진다.
즉, 트리 자료구조는 부모 노드와 자식 노드로 구성되어 노드 간의 계층적 구조를 표현하는 비선형 자료구조를 말한다,

트리 자료구조는 최상위 노드에서 시작한다. 최상위 노드는 부모 노드가 없으며, 루트 노드라 한다.

루트 노드는 0개 이상의 자식 노드를 갖고, 자식 노드가 없는 노드를 리프 노드라고 한다.

노드들의 객체로 구성된 트리 자료구조를 DOM이라 한다.

노드 객체의 타입

다음과 같은 HTML 문서를 렌더링 엔진이 파싱한다고 하면 이런식으로 DOM을 생성한다.

<!DOCTYPE html>
<html>
	<head>
    	<meta ...>
        <link ...>
    </head>
    <body>
    	<ul>
        	<li id="apple ">Apple</li>
            <li id="banana">Banana</li>
            <li id="orange">Orange</li>
        </ul>
    </body>
</html>

이처럼 DOM은 노드 객체의 계층적인 구조를 가지며, 노드 객체는 12가지 종류가 있는데 그 중 가장 중요한 노드 타입은 4가지다.

문서노드
작성자가 생각하기에 가장 중요하다고 생각하는 부분이다.
문서 노드는 DOM 트리 최상위에 존재하는 루트 노드로서 document 객체를 가리킨다. document 객체는 브라우저가 렌더링한 HTML 문서 전체를 가리키는 객체로서 전역 객체 window의 document 프로퍼티에 바인딩되어 있다.
따라서 문서 노드는 window.document, document로 참조할 수 있다.

우리가 평소 js로 어떤 노드(노드가 아직 어렵게 느껴진다면, 해당 id에 접근한다고 생각해보자)에 접근하려고 할 때,

document.getElementById()
document.querySelector()
document.getElementByTagName()
...

이런 함수를 사용해 본 적이 있을 것이다. 공통점은 모두 앞에 document가 항상 붙게 되는데 이것은

window.document.getElementById()
window.document.querySelector()
window.document.getElementByTagName()
...

이런식으로 표현할 수 있다.

무슨 말이냐면 window.document, document는 서로 같은 객체를 호출한다는 것이다.
통상적으로 window를 생략하여 표현하기 때문에 document만 사용하여 표현하는 것이고 전역 객체 window 안에 document 객체가 존재한다는 것이다.

전역 객체 window가 궁금하다면 개발자 도구에 window를 검색하면 된다.

이것은 설명이 길어지기 때문에 간략하게 설명하면
window 안의 객체에서 사진 가장 하단에 document 를 확인했다면 이제 이해가 될 것이다.
그냥 단순하게 객체를 호출하는 방법이다.

필자는 이것이 왜 중요하다고 생각하냐면, 결국 브라우저 환경에서 모든 js 코드는 script 태그에 의해 모두 분리되어 있어도 하나의 전역 객체 window를 공유하기 때문에 모든 js 코드는 전역 객체 window의 document 프로퍼티데 바인딩 되어 있는 하나의 document 객체를 바라본다.

좀 더 쉽게 예시를 들면 다음과 같다.

아까 개발자 도구에서 window를 찍었을 때, 아래 하단에 여러가지 프로퍼티를 포함하고 있었다. 이 중 우리가 흔히 아는 함수도 여럿 보인다.

대표적으로 우리가 흔히 사용하는 alert도 window 객체에 포함된다.

만약 내가 변수를 선언한다면?

이 기이한 모습이 보이는가??! 내가 선언한 변수가 전역 객체에 등록됐다.

설명이 너무 길이지니 전역 객체 window를 나중에 꼭 공부하길 바란다.

어쨌든 결국 모든 js는 하나의 전역 객체를 공유하고! window의 document 프로퍼티에 바인딩 되어 있는 하나의 document 객체를 바라본다!

즉, HTML 문서당 document 객체는 유일하다!

>> 문서 노드, 즉 document 객체는 DOM 트리의 루트 노드이므로 DOM 트리의 노드들에 접근하기 위한 진입점 역할을 담당한다. 즉, 요소, 어트리뷰트, 텍스트 노드에 접근하려면 문서 노드(document)를 통해야 한다.

그럼 다시 정리해서 요소를 접근하기 위해, 어트리뷰트를 접근하기 위해, 텍스트 노드에 접근하기 위해 문서 노드를 사용한다는 것은 다음과 같다.

요소를 접근하기 위해
document.getElementsByTagName("div")

어트리뷰트를 접근하기 위해
document.getElementById("id")
document.getElementByClassName("class")

텍스트 노드를 접근하기 위해
var myDiv = document.getElementById('myDiv');

// 해당 요소의 첫 번째 자식 노드는 텍스트 노드이므로 접근 가능 (이 문장이 이해가 안 된다면 이 부분은 다음 포스팅에서 설명하겠습니다.)
var textNode = myDiv.firstChild;
// 텍스트 노드의 내용을 변경
textNode.nodeValue = 'This text has been changed!';

결국 모든 요소, 노드에 접근하려면 문서 노드(document)를 통해야 한다!

이후 노드 3가지 타입 (요소 노드, 어트리뷰트 노드, 텍스트 노드), 노드를 취득하는 방법, 노드 취득 시 고려해야 될 점 등은 다음 포스팅에서 확인바랍니다!🔥

0개의 댓글