DOM Enlightenment 정리 (1장)

Kay·2023년 2월 23일
0

DOM-Enlightenment-정리

목록 보기
1/2

1. Node Overview


1.1 The Document Object Model (a.k.a the DOM) Is a Hierarcy/Tree of Javascript Node Objects

  • HTML 문서가 브라우저에 의해 구문 분석되고 노드 개체의 트리 구조로 변환됨
  • DOM의 목적은 Javascript를 사용하여 문서를 스크립팅하기 위한 프로그래밍 인터페이스를 제공하기 위함

1.2 Node Object Types


1.3 Subnode Objects Inherit From the Node Object

  • 모든 노드 타입은 NODE로부터 상속됨과 상속 체인은 길 수 있다는 점이 중요 포인트
  • NODE는 Javascript의 모든 객체와 마찬가지로 Object.prototype에서 상속
- Object < Node < Element < HTMLElement < (e.g., HTML*Element)
- Object < Node < Attr (this is desperated in DOM4)
- Object < Node < CharacterData < Text
Object < Node < Document < HTMLDocument
Object < Node < DocumentFragment
  • 일반적인 DOM 트리의 각 노드 개체는 NODE에서 속성과 메서드를 상속
<a href="#">Hi</a>

<script>
	var nodeAnchor = document.querySelector('a');
    var props = [];

    for (var key in nodeAnchor) {
    	props.push(key)l
    }

    // 알파벳 순으로 속성(properties)와 메서드(methods)가 로그에 출력됨
    console.log(props.sort());
</script>

1.4 Properties and methods for working with nodes
모든 노드들은 속성과 메서드를 상속받아 DOM을 활용할 수 있도록 함 (DOM 순회, 검사, 추가, 조작...)

  • Node properties
    • childNodes
    • firstChild
    • lastChild
    • nextSibling
    • nodeName
    • nodeType
    • nodeValue
    • parentNode
    • previousSibling
  • Node methods
    • appendChild()
    • cloneChhild()
    • compareDocumentPosition()
    • contains()
    • hasChildNodes()
    • insertBefore()
    • isEqualNode()
    • removeChild()
    • replaceChild()
  • Document methods
    • document.createElement()
    • document.createTextNode()
  • HTML *Element properties
    • innerHTML
    • outerHTML
    • textContent
    • innerText
    • outerText
    • firstElementChild
    • lastElementChild
    • nextElementChild
    • previousElementChild
    • children
  • HTML element method
    • insertAdjacentHTML()

1.5 Identifying the Type and Name of a Node
모든 노드에는 Node에서 상속된 nodeType과 nodeName 속성이 존재

<a href="#">Hi</a>

<script>
  // Node.DOCUMENT_TYPE_NODE
  console.log(document.doctype.nodeName); // html
  console.log(document.doctype.nodeType); // 10

  // Node.DOCUMENT_NODE
  console.log(document.nodeName); // #document
  console.log(document.nodeType); // 9

  // Node.DOCUMENT_FRAGMENT_NODE
  createDocumentFragment()
  console.log(document.createDocumentFragment().nodeName); // #document-fragment
  console.log(document.createDocumentFragment().nodeType); // 11

  // Node.ELEMENT_NODE
  console.log(document.querySelector('a').nodeName) // A
  console.log(document.querySelector('a').nodeType) // 1

  // Node.TEXT_NODE
  console.log(document.querySelector('a').firstChild.nodeName) // #text
  console.log(document.querySelector('a').firstChild.nodeType) // 3
</script>

1.6 Getting a Node's Value

  • nodeValue 속성은 텍스트와 주석 제외 대부분의 노드 유형에서 null을 반환
  • 즉, Text 노드에서 텍스트 문자열을 추출할 때 주로 사용
<a href="#">Hi</a>

<script>
	console.log(document.querySelector('a').firstChild.nodeValue) // Hi
</script>

1.7 Using Javascript Methods to Create Element and Text Nodes

  • 1.1 에서 학습했듯 HTML 문서는 브라우저에 의해 구문 분석되고 노드 개체의 트리 구조로 변환됨
  • 하지만, 다음 두 방법으로 Javascript로 노드를 생성할 수 있음
    • createElement()
    • createTextNode()
<!DOCTYPE html>
<html lang="en">
  <body>

    <script>
    	var elementNode = document.createElement('div');
        var textNode = document.createTextNode('Hi');
    </script>
  </body>
</html>

1.8 Using Javascript Strings to Create and Add Element and Text Nodes to the DOM

  • innerHTML, outerHTML, textContent properties를 사용하여 DOM에 노드를 추가하는 방법
<!DOCTYPE html>
<html lang="en">
  <body>
  	<div id="A"></div>
    <div id="B"></div>
    <div id="C"></div>
    <div id="D"></div>
    <div id="E"></div>

    <script>
    	document.getElementById('A').innerHTML = '<string>Hi</string>';
        document.getElementById('B').outerHTML = '<div id="B" class="new">What is Shaking</div>';
        document.getElementById('C').textContent = 'dude';
        document.getElementById('D').innerText = 'Keep it';
        document.getElementById('E').outerText = 'real!';

        console.log(document.body.innerHTML);

        /**
        * <div id="A"><strong>Hi</string></div>
        * <div id="B" class="new">What is Shaking</div>
        * <div id="C">dude</div>
        * <div id="D">Keep it</div>
        * real!
        */
    </script>
  </body>
</html>
  • insertAdjacentHTML()를 사용하여 DOM에 노드를 추가하는 방법
<!DOCTYPE html>
<html lang="en">
  <body>
  	<i id="elm">how</i>

    <script>
    	var elm = document.getElementById('elm');
    	elm.insertAdjacentHTML('beforebegin', '<span>Hey-</span>');
        elm.insertAdjacentHTML('afterbegin', '<span>dude-</span>');
        elm.insertAdjacentHTML('beforeend', '<span>are</span>');
        elm.insertAdjacentHTML('afterend', '<span>you?</span>');

        console.log(document.body.innerHTML);

        /**
        * <span>Hey-</span>
        * <i id="A"><span>dude-</span>how<span>are</span></i>
        * <span>you?</span>
        */
    </script>
  </body>
</html>

1.9 Extracting Parts of the DOM Tree as Javascript Strings

  • innerHTML, outerHTML, textContent properties를 사용하여 노드의 문자열 추출하기
<!DOCTYPE html>
<html lang="en">
  <body>
  	<div id="A"><i>Hi</i></div>
    <div id="B">Dude<strong> !</strong></div>

    <script>
    	console.log(document.getElementById('A').innerHTML); // '<i>Hi</i>'
        console.log(document.getElementById('B').textContent) // 'Dude !'
        console.log(document.getElementById('B').innerText) // 'Dude !'
        console.log(document.getElementById('B').outerText) // 'Dude !'
    </script>
  </body>
</html>

1.10 Using appendChild() and insertBefore() to Add Node Objects to the DOM

  • appendChild()
<!DOCTYPE html>
<html lang="en">
  <body>
  	<p>Hi</p>

    <script>
    	var elementNode = document.createElement('strong');
        var textNode = document.createTextNode(' Dude');

        document.querySelector('p').appendChild(elementNode);
        document.querySelector('strong').appendChild(textNode);

        console.log(document.body.innerHTML);
        // <p>Hi<strong> Dude</strong></p>
    </script>
  </body>
</html>
  • insertBefore()
<!DOCTYPE html>
<html lang="en">
  <body>
  	<ul>
    	<li>2</li>
        <li>3</li>
    </ul>

    <script>
    	var text1 = document.createTextNode('1');
        var li = document.createElement('li');
        li.appendChild(text1);

        var ul = document.querySelector('ul');

       ul.insertBefore(li, ul.firstChild);

       console.log(document.body.innerHTML);
       /**
        * <ul>
        *   <li>1</li>
        *   <li>2</li>
        *   <li>3</li>
        * </ul>
        */
    </script>
  </body>
</html>

1.11 Using removeChild() and replaceChild() to Remove and Replace Nodes

  • removeChild()
<!DOCTYPE html>
<html lang="en">
  <body>
  	<div id="A">Hi</div>
    <div id="B">Dude</div>

    <script>
    	// remove element node
    	var divA = document.getElementById('A');
        divA.parentNod.removeChild(divA);

        // remove text node
        var divB = document.getElementById('B').firstChild;
        divB.parentNod.removeChild(divB);

       console.log(document.body.innerHTML);
       // <div id="B"></div>
    </script>
  </body>
</html>
  • replaceChild()
<!DOCTYPE html>
<html lang="en">
  <body>
  	<div id="A">Hi</div>
    <div id="B">Dude</div>

    <script>
    	// replace element node
    	var divA = document.getElementById('A');
        var newSpan = document.createElement('span');
        newSpan.textContent = 'Howdy';
        divA.parentNod.replaceChild(newSpan, divA);

        // replace text node
        var divB = document.getElementById('B').firstChild;
        var newText = document.createTextNode('buddy');
        divB.parentNod.replaceChild(newText, divB);

       console.log(document.body.innerHTML);
    </script>
  </body>
</html>

1.12 Using cloneNode() to Clone Nodes

<!DOCTYPE html>
<html lang="en">
  <body>
  	<ul>
    	<li>Hi</li>
        <li>there</li>
    </ul>

    <script>
    	// cloneNode()에 파라미터 없을 경우 UL만 복제
        var cloneOnlyUL = document.querySelector('ul').cloneNode();
        // cloneNode()에 파라미터로 true를 보내면 자식 노드까지 복제
        var cloneAllUL = document.querySelector('ul').cloneNode(true);

       console.log(cloneOnlyUL.constructor); // logs HTMLUListElement()
       console.log(cloneOnlyUL.innerHTML); // logs (an empty string) as only the ul was ccloned

       console.log(cloneAllUL.constructor); // logs HTMLUListElement()
       console.log(cloneAllUL.innerHTML); // logs <li>Hi</li><li>there</li>
    </script>
  </body>
</html>

1.13 Grokking Node Collections (i.e., NodeList and HTMLCollection)

  • 노드 트리에서 노드 그룹을 선택하거나 접근하려면 해당 노드들이 NodeList (ex. document.querySelectorAll('*') 또는 HTMLCollection)에 속해 있어야 한다.
  • array-like object collection의 특징
    • A Collection can be either live or static. This means the nodes contained in the collection are either literally part of the live document or a snapshot of the live document.
      • cf) 스냅샷: 특정 시점의 리파지토리에 보관
    • By default, nodes are sorted inside the collection by tree order. This means the order matches the linear path from tree trunk to branches.
    • The collections have a length property that reflects the number of elements in the list.

1.14 Getting a List/Collection of All Immediate Child Nodes

  • childNodes 속성을 통해 내부 직계 자식 노드 목록 확인
  • childNodes에는 Element 노드뿐만이 아니라 다른 모든 노드 유형(ex. Text, Comment 등)이 포함되어 있음
<!DOCTYPE html>
<html lang="en">
  <body>
  	<ul>
    	<li>Hi</li>
        <li>there</li>
    </ul>

    <script>
       var ulElementChildNodes = document.querySelector('ul').childNodes;

       console.log('1', ulElementChildNodes);
       // [0: text, 1: li, 2: text, 3: li, 4: text]

       Array.prototype.forEach.call(ulElementChildNodes, function(item) {
       	 console.log('2', item);
       })
    </script>
  </body>
</html>

1.15 Converting a NodeList or HTMLCollection to a Javascript Array

  • NodeList과 HTML Collection은 배열과 유사하지만 배열 메서드를 상속하는 진정한 Javascript 배열은 아님
  • Array.isArray() 함수를 사용하여 이를 확인할 수 있음
<!DOCTYPE html>
<html lang="en">
  <body>
  	<a href="#"></a>

    <script>
       console.log(Array.isArray(document.links));
       // returns false, it's an HTMLCollection not an Array
       console.log(Array.isArray(document.querySelectorAll('a')));
       // return false, it's a NodeList not an Array
    </script>
  </body>
</html>

cf) NodeList과 HTML Collection을 실제 Javascript 배열로 변환하면 여러 가지 이점이 있음

  • DOM에 살아있지 않은 라이브 리스트를 생성하는 기능 제공
  • 목록을 배열로 변환하면 Javascript Array 객체가 제공하는 메서드에 접근 가능
<!DOCTYPE html>
<html lang="en">
  <body>
  	<a href="#"></a>

    <script>
       console.log(Array.isArray(Array.prototype.slice.call(document.links)));
       // returns true
       console.log(Array.isArray(Array.prototype.slice.call(document.querySelectorAll('a'))));
       // return false
    </script>
  </body>
</html>

1.16 Traversing Nodes in the DOM

  • node reference (ex. document.querySelector('ul'))로부터 DOM을 순회하여 다른 노드 참조를 얻을 수 있음
  • ex. parentNode, firstChild, lastChild, nextSibling, previousSibling, firstElementChild, lastElementChild, previousElementSibling, nextElementSibling, children, parentElemtn
<!DOCTYPE html>
<html lang="en">
  <body>
  	<ul>
    	<!-- comment -->
    	<li id="A">Hi</li>
        <li id="B">there</li>
    	<!-- comment -->
    </ul>

    <script>
       // cache selection of the ul
       var ul = document.querySelector('ul');

       // what is the parentNode of the ul?
       console.log(ul.parentNode.nodeName); // logs body

       // what is the first child of the ul?
       console.log(ul.firstChild.nodeName); // logs comment

       // what is the last child of the ul?
       console.log(ul.lastChild.nodeName); // logs text not comment, because there is a line break

       // what is the nextSibling child of the li?
       console.log(ul.querySelector('#A').nextSibling.nodeName); // logs text

       // what is the previousSibling of the last li?
       console.log(ul.querySelector('#B').previousSibling.nodeName); // logs text

       // what is the first child of the ul?
       console.log(ul.firstElementChild.nodeName); // logs li

       // what is the last child of the ul?
       console.log(ul.lastElementChild.nodeName); // logs li

       // what is the nextSibling child of the li?
       console.log(ul.querySelector('#A').nextElementSibling.nodeName); // logs li

       // what is the previousSibling of the last li?
       console.log(ul.querySelector('#B').previousElementSibling.nodeName); // logs li

       // what are the element only child nodes of the ul?
       console.log(ul.children); // HTMLCollection, all child nodes including text nodes

        // what is the parent element of the li?
       console.log(ul.firstElementChild.nodeName); // logs ul
    </script>
  </body>
</html>

1.17 Verifying a Node Position in the DoM Tree with Contains() and compareDocumentPosition()

  • contains() 메서드를 사용하면 노드가 다른 노드 안에 포함되어 있는지 여부 확인 가능
<!DOCTYPE html>
<html lang="en">
  <body>
    <script>
    	var inside = document.querySelector('html').contains(document.querySelector('body'));

        console.log(inside); // logs true
    </script>
  </body>
</html>
  • compareDocumentPosition() 메서드를 사용하면 노드가 다른 노드와의 관계에 대해 알 수 있음
  • 둘 이상의 관계 유형을 가질 수 있기 때문에 다소 혼란스러울 수 있음
    • ex. 노드가 (16)을 포함하고 (4)보다 앞에 있는 경우 compareDocumentPosition()반환된 값은 20임
0 - Elements are identical. (동일)
1 - DOCUMENT_POSITION_DISCONNECTED
    // Set when selected node ans passed-in node are not in the same doucment (존재하지 않음)
2 - DOCUMNET_POSITION_PRECEDING
    // Set when passed-in node is following selected nnode. (선택된 거 앞에)
4 - DOCUEMNT_POSITION_FOLLOWING
    // Set when passed-in node is following selected node. (선택된 거 뒤에)
8 - DOCUEMNT_POSITION_CONTAINS
    // Set when passed-in node is an anscestor of selected node. (선택된 거 조상)
16, 10 - DOCUEMNT_POSITION_CONTAINED_BY (16, 10 in headecimal)
    // Set when passed-in node is descendant of selected node. (선택된 거 자손)

1.18 Determining Whether Two Nodes Are Identical

  • DOM3에 따르면 두 개의 노드가 같다고 판단하기 위해 필요한 조건들
    • 두 개의 노드는 같은 타입이어야 한다.
    • nodeName, localName, namespaceURI, prefix, nodeValue의 스트링 요소가 같아야 한다. (이는 둘 다 null 또는 같은 길이이며 같은 문자열들임을 의미)
    • NameNodeMaps가 같다. (이는 둘 다 null 또는 같은 index에 같은 노드를 가지고 있음을 의미)
    • childNodes NodeLists가 같다. (이는 둘다 null 또는 같은 index에 같은 노드를 가지고 있음을 의미 + 정규화는 nomalization에 영향을 줄 수 있기 때문에 노드 비교 전 정규화가 필요)
      cf) 노드 정규화 : Element 안에서 띄어쓰기 같은 text가 있을 경우 하나의 dom을 차지한다. 이런 경우 한 줄로 깔끔하게 정규화할 수 있다.
  • DOM에서 isEqualNode() 메서드를 호출하는 것은 매개 변수로 전달한 노드와 동일한지 true/false로 반환
<!DOCTYPE html>
<html lang="en">
  <body>

  	<input type="text" />
    <input type="text" />

    <textarea>foo</textarea>
    <textarea>bar</textarea>

    <script>
    	// logs true, because they are exactly identical
        var input = document.queryselectorAll('input');
        console.log(input[0].isEqualNode(input[1]));

        // logs false, beacuase the child text node is not the same
        var textarea = document.querySelectorAll('textarea');
        console.log(textarea[0].isEqulNode(textarea[1]));
    </script>
  </body>
</html>

cf) 두 노드가 정확히 같은지가 아닌 두 노드가 같은 reference를 참조하고 있는지 알고 싶다면 === 연산자를 통해서 확인할 수 있음

0개의 댓글