DOM Interface

Yeongjong Kim·2021년 12월 27일
0

typescript를 사용하다보면 DOM과 관련되며, 이미 정의되어 있는 interface를 사용할 때가 있다.

예를 들어 ChildNode, HTMLElement가 해당한다.

그런데 정말 헷갈린다. ChildNode, HTMLElement 뭐가 다른거지?

그래서 조사해보았다.

1. DOM Node, DOMElement 차이

1.1 DOM Node

NODE의 의미는 부모 자식의 관계에 있다. 아래 html document 구조를 보면 부모 자식 형제 관계에 따라 표현되고 있다. html은 head, body 자식 노드를 가지고 있다. 이러한 태그형 node(html element) 뿐만아니라 text node도 node 이기 때문에 부모 형제 관계를 가지고 있다. 따라서 text node도 before, after, parentElement 등의 관계된 node를 찾기 위한 메서드를 포함하고 있다.

<html>
  <head>
    <title> tory </title>
  </head>
  <body>
    <h1> Let me find my darling </h1>
  </body>
</html>

1.1.1 Node Types

노드는 타입을 가지고 있다. 각 타입은 node가 가진 기능을 포함하며, 그외 자신만의 고유 기능 혹은 정보를 포함한다.

  • 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

1.2 DOM Element

이 것은 위에서 살펴본 Node.ELEMENT_NODE 타입의 Node이다. 즉 특수한 Node이다. 이 노드는 tag를 가진 Node라고 생각하면 쉽다. 즉 text node, attribute node는 해당하지 않는다.

new Text('test').type === Node.ELEMENT_NODE // false

1.2.1 instanceof 사용시 주의할 점

const paragraph = document.querySelector('p');
paragraph instanceof Node;        // => true
paragraph instanceof HTMLElement; // => true

paragraph는 Node, HTMLElement 모두의 개체이기 때문에 위와 같이 모두 true의 값을 반환한다. 따라서 만약 HTMLElement 처럼 특수한 node만을 취급할 것이라면 type 번호를 확인하거나 HTMLElement와 같이 특수한 타입에서 instanceof를 사용하자.

그렇다면 $elem instanceof HTMLElement와 $elem.nodeType === Node.ELEMENT_NODE는 같을까?

결론부터 말하면 다르다.

const $elem = document.createElement('div');
$elem.innerHTML = '<svg></svg>';

$elem.childNodes[0] instanceof HTMLElement // false

$elem.childNodes[0].nodeType === Node.ELEMENT_NODE // true
왜 다를지 유추해보기...
  1. 1.3 섹션의 법칙에 의해 childNodes 메서드를 사용한 결과는 모두 Node로 인식된다.

=> 이 것은 사실이 아님.

children과 childNode 모두 instanceof에 의해 false를 반환하다.

$elem.children[0] instanceof HTMLElement // false

아직 이유를 찾지 못했음 답은 기술 부채로 나중에 찾아보기로 한다.

수정사항 답 > DOM은 상속 계층 구조로 관리된다. 이때, HTMLElement는 Element로 부터 상속을 받게되는데, SVG의 경우 SVGElement라는 별개의 interface에 의해 관리된다. 즉 모든 Element가 HTMLElement는 아니다. SVG, XML의 경우 별로도 관리되니 해당 interface를 사용할 경우 주의해서 사용하자.

출처1: https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
출처2: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model

1.3 Node와 Element의 차이점

node의 메서드는 항상 Node 혹은 NodeList를 반환하고, element의 메서드는 HTMLElement 혹은 HTMLCollection을 반환한다.

node.parentNode; // Node or null
node.firstChild; // Node or null
node.lastChild;  // Node or null
node.childNodes; // NodeList
node.parentElement; // HTMLElement or null
node.children;      // HTMLCollection

여기서 children과 childNodes의 차이를 옅볼 수 있다.

children은 태그 요소만 포함하기 때문에 text 노드를 포함하지 않는다.

<p>
  <b>Thank you</b> for visiting my web page!
</p>
const paragraph = document.querySelector('p');
paragraph.childNodes; // NodeList:       [HTMLElement, Text]
paragraph.children;   // HTMLCollection: [HTMLElement]

childNodes는 b 노드와 그 이후 text를 포함하는 반면 children은 b 노드만 포함한다.

ChildNode와 HTMLElement의 차이

이제 알겠는가? ChildNode는 text를 포함한다. 하지만 HTMLElement는 포함하지 않는다.

typescript의 interface 측면에서 차이

interface를 까보면 ChildNode는 단순하게 Node를 상속받고 before, after, remove, replaceWith라는 메서드만 가지고 있다.

하지만 HTMLElement는 모든 Element를 포함하는 인터페이스이기 때문에 Element에 대한 attibute 정보라든지, 모든 Element가 포함해야하는 addEventListener 같은 추가 정보를 가지고 있다.

따라서 이 interface는 완전히 다르다고 봐야한다. 둘을 구분해서 필요할 때 사용하도록 하자.

출처

profile
Front 💔 End

0개의 댓글