DOM(Document Object Model)은 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료구조이다.
HTML 문서는 HTML 요소들의 집합으로 이뤄지며, HTML 요소는 중첩 관계를 갖는다.
모던 자바스크립트 Deep Dive, p.677, 그림 39-1 참조
HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다.
모던 자바스크립트 Deep Dive, p.678, 그림 39-2 참조
HTML 요소 간에는 중첩 관계에 의해 계층적인 부자 관계가 형성된다.
이러한 HTML 요소 간의 부자 관계를 반영하여 HTML 요소를 객체화한 모든 노드 객체들을 트리 자료 구조로 구성한다.
트리 자료구조
모던 자바스크립트 Deep Dive, p.678, 그림 39-3 참조
트리 자료구조는 부모 노드와 자식 노드로 구성되어 노드 간의 계층적 구조를 표현하는 비선형 자료구조이다.
트리 자료 구조는 하나의 최상위 노드에서 시작한다. 최상위 노드는 루트 노드라고도 하고, 0개 이상의 자식 노드를 갖는다.
자식 노드가 없는 노드를 리프 노드라 한다.
노드 객체들로 구성된 트리 자료구조를 DOM이라 하고, DOM 트리라고 부르기도 한다.
모던 자바스크립트 Deep Dive, p.679, 그림 39-4 참조
렌더링 엔진은 HTML 문서를 파싱하여 그림 39-4와 같이 노드 객체의 계층적인 구조로 구성된 DOM을 생성한다. 노드 객체는 총 12개의 노드 타입이 있고, 그 중 중요한 4개의 노드 타입은 아래와 같다.
문서 노드
문서 노드는 DOM 트리의 최상위에 존재하는 루트 노드로서 document 객체를 가리킨다.
window.document 또는 document로 문서 노드를 참조할 수 있다.
HTML 문서 당 document 객체는 유일하다.
문서 노드는 DOM 트리의 노드들에 접근하기 위한 진입점(entry point) 역할을 한다.
즉, 요소, 어트리뷰트, 텍스트 노드에 접근하려면 문서 노드를 통해야 한다.
요소 노드
요소 노드는 HTML 요소를 가리키는 객체로, 문서의 구조를 표현한다.
요소 노드는 HTML 요소 간의 중첩에 의해 부자 관계를 가지며, 이를 통해 정보를 구조화한다.
어트리뷰트 노드
어트리뷰트 노드는 HTML 요소의 어트리뷰트를 가리키는 객체이다.
어트리뷰트 노드는 부모 노드와 연결되어 있지 않고 요소 노드에만 연결되어 있다.
즉, 어트리뷰트 노드는 부모 노드가 없으므로 요소 노드의 형제(sibling) 노드는 아니다.
따라서 어트리뷰트 노드에 접근하여 어트리뷰트를 참조하거나 변경하려면 먼저 요소 노드에 접근해야 한다.
텍스트 노드
텍스트 노드는 HTML 요소의 텍스트를 가리키는 객체로, 문서의 정보를 표현한다.
텍스트 노드는 요소 노드의 자식 노드이며, 자식 노드를 가질 수 없는 리프 노드이다.
즉, 텍스트 노드는 DOM 트리의 최종단으로, 텍스트 노드에 접근하려면 먼저 요소 노드에 접근해야 한다.
DOM을 구성하는 노드 객체는 ECMAScript 사양에 정의된 표준 빌트인 객체가 아니라 브라우저 환경에서 추가적으로 제공하는 호스트 객체이다.
하지만 노드 객체도 자바스크립트 객체이므로 프로토타입에 의한 상속 구조를 갖는다.
모던 자바스크립트 Deep Dive, p.681, 그림 39-5 참조
그림 39-5와 같이 모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받는다.
문서 노드는 Document, HTMLDocument 인터페이스를 상속받는다.
어트리뷰트 노드는 Attr 인터페이스를 상속받는다.
텍스트 노드는 CharacterData 인터페이스를 상속받는다.
요소 노드는 Element 인터페이스와 추가적으로 HTMLElement와 태그의 종류별로 세분화된 인터페이스를 상속받는다.
<!DOCTYPE html>
<html>
<body>
<input type="text">
<script>
// input 요소 노드 객체를 선택
const $input = document.querySelector('input');
// input 요소 노드 객체의 프로토타입 체인
console.log(
Object.getPrototypeOf($input) === HTMLInputElement.prototype,
Object.getPrototypeOf(HTMLInputElement.prototype) === HTMLElement.prototype,
Object.getPrototypeOf($HTMLElement.prototype) === Element.prototype,
Object.getPrototypeOf($Element.prototype) === Node.prototype,
Object.getPrototypeOf($Node.prototype) === EventTarget.prototype,
Object.getPrototypeOf($EventTarget.prototype) === Object.prototype,
); // 모두 true
</script>
</body>
</html>
모던 자바스크립트 Deep Dive, p.682, 그림 39-6 참조
노드 객체는 공통된 기능일수록 프로토타입 체인의 상위에, 개별적인 고유 기능일수록 프로토타입 체인의 하위에 프로토타입 체인을 구축하여 노드 객체에 필요한 기능(프로퍼티와 메서드)을 제공하는 상속 구조를 갖는다.
DOM은 HTML 문서의 계층적 구조와 정보를 표현하는 것은 물론 노드 객체의 종류, 즉 노드 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API로 제공하고 이를 통해 HTML의 구조나 내용 또는 스타일을 동적으로 조작할 수 있다.
HTML의 구조나 내용 또는 스타일 등을 동적으로 조작하기 위해선 먼저 요소 노드를 취득해야 한다.