시작은 React reconciliation, 그 전에는 React18에 적용된 Suspense, useTransition 등에 대한 궁금증에서부터였다. 관련 글을 읽다보니 자주 나오는 개념인 DOM node, element 등에 대한 이해도를 높이고자 정리하는 글
Document Object Model, DOM, 은 HTML 혹은 XML 문서를 각 노드가 문서의 객체인 트리 구조로서 처리하기 위한 interface
이다. DOM은 tree를 query (불러오기), 구조와 스타일을 변경하기 위한 여러 메소드들을 제공하기도 한다.
DOM은 또한 element라는 단어를 사용한다: node와 상당히 비슷하다. 그럼 두개는 무엇이 다른지 알아보자
node와 element의 차이를 알아보기 위해서 node가 무엇인지 알아보는게 중요하다.
더 큰 관점에서 보면 DOM document는 노드 계층으로 구성된다. 각 노드는 부모와 자식 혹은 각각 가질 수 있다. 다음 HTML 문서를 살펴보자
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<!-- Page Body -->
<h2>My Page</h2>
<p id="content">Thank you for visiting my web page!</p>
</body>
</html>
위 html은 다음과 같은 계층으로 표현이 가능하다.
ㄴ DOCTYPE: html
ㄴ HTML
ㄴHEAD
ㄴTITLE
ㄴ#text: My Page
ㄴBODY
ㄴ#comment: Page Body
ㄴH2
ㄴtext: My Page
ㄴP id="content"
ㄴ#text: Thank you for visiting my web page!
<html>
은 <head>
and <body>
node들을 자식으로 가지고 있는 document tree의 node이다.
<body>
또한 세개의 자식을 갖는 노드다. <!-- Page Body -->
, heading <h2>
, 그리고 paragraph <p>
. <body>
node의 부모는 <html>
node다.
HTML document의 tag들은 노드를 대표한다. 더 흥미로운건 text 또한 노드이다. paragraph node <p>
는 text node "Thank you for visiting my web page!"
를 자식으로 갖는다.
DOM Node 인터페이스를 살펴보면 Node.nodeType
속성으로 노드의 타입을 구분할 수 있다.
Node.nodeType
는 노드의 타입을 나타내는 다음의 값들이 있다.
Node.ELEMENT_NODE
Node.ATTRIBUTE_NODE
Node.TEXT_NODE
Node.CDATA_SECTION_NODE
Node.PROCESSING_INSTRUCTION_NODE
Node.COMMENT_NODE
Node.DOCUMENT_NODE
Node.DOCUMENT_TYPE_NODE
Node.DOCUMENT_FRAGMENT_NODE
Node.NOTATION_NODE
위 상수들은 노드 유형을 의미 있게 나타낸다: 예를 들면, Node.ELEMENT_NODE
은 element node를 나타낸다.
예를 들어, paragraph node를 선택하고 선택된 노드의 타입을 살펴보자
const paragraph = document.querySelector('p');
paragraph.nodeType === Node.ELEMENT_NODE; // => true
예상대로 paragraph.nodeType
은 paragraph가 element인 것을 알 수 있듯, Node.ELEMENT_NODE
값을 가지고 있다.
paragraph는 또한 text node를 가지고 있다.
const paragraph = document.querySelector('p');
const firstChild = paragraph.childNodes[0];
firstChild.nodeType === Node.TEXT_NODE; // => true
또한 노드 타입에는 노드의 전체 document tree를 나타내는 Node.DOCUMENT_NODE
타입이 있다.
document.nodeType === Node.DOCUMENT_NODE; // => true
DOM Node가 무엇인지 잘 파악했으니 element와 구분점을 알아보자.
node에 대해 이해가 높다면 답은 명확하다: element은 Node.ELEMENT_NODE
라는 특정 타입의 노드이다.
간단하게 element는 HTML의 tag를 사용해 작성된 node라고 볼 수 있다. <html>
, <head>
, <title>
, <body>
, <h2>
등 모두 tag로 대변될 수 있기 때문에 element이다.
하지만 document type, comment, text 노드는 모두 tag로 작성되지 않았기 때문에 element가 아니다.
Node
는 node의 constructor이고 HTMLElement
는 Javascript DOM에서 element의 constructor이다. paragraph은 node이면서 element이기에 Node
와 HTMLElement
의 instance다.
const paragraph = document.querySelector('p');
paragraph instanceof Node; // => true
paragraph instanceof HTMLElement; // => true
element는 node의 subtype으로도 볼 수 있다: 고양이(element)와 동물(node)의 관계
node와 element의 구분을 차치하고, 오직 node 혹은 오직 element를 위한 DOM 속성들을 구분해볼 필요가 있다.
다음 Node 타입의 속성은 Node 혹은 NodeList로 평가된다.
node.parentNode; // Node or null
node.firstChild; // Node or null
node.lastChild; // Node or null
node.childNodes; // NodeList
하지만 다음 속성들은 element 혹은 element collection(HTMLCollection
)이다.
node.parentElement; // HTMLElement or null
node.children; // HTMLCollection
node.childNodes
와 node.children
모두 children list를 반환하는데 왜 구분이 되어 있을까? 다음 예제 코드로 살펴보자
<p>
<b>Thank you</b> for visiting my web page!
</p>
그 후 paragraph의 childNodes
와 children
을 살펴보면,
const paragraph = document.querySelector('p');
paragraph.childNodes; // NodeList: [HTMLElement, Text]
paragraph.children; // HTMLCollection: [HTMLElement]
paragraph.childNodes
collection은 2개의 노드를 갖는다: bold element인 <b>Thank you</b>
와 text node인 for visiting my web page!
하지만 paragraph.children
collection은 bold element인 <b>Thank you</b>
만 가지고있다. paragraph.children
은 오직 element만 가지고 있을 수 있기 때문에 타입이 element(Node.ELEMENT_NODE
)가 아닌 text 타입(Node.TEXT_NODE
)를 갖는 text node는 포함되지 않는다.
DOM document는 노드 의 계층적 collection이다. 각 node는 부모, 자식 혹은 둘다 가질 수 있다.
즉 HTML의 계층을 표현할 수 있는 모든것은 다 Node다.
element은 Node.ELEMENT_NODE
라는 특정 타입의 노드로 HTML 문서의 tag를 사용해 작성된 node다.
Node는 element를 포함한다: 동물(Node)과 고양이(element)의 관계. 또한 Node이면서 element인 경우도 있다: paragraph.
다만, Document node (Node.DOCUMENT_NODE
)은 절대 부모를 가질 수 없다.