노드 (Node)
작성
1. DOM은 Node로 이루어진 트리다
DOM이란,HTML을 나타내는 노드 객체들의 트리 구조를 말한다.- HTML 문서를 작성할 때, HTML 콘텐츠를 다른 HTML 콘텐츠 내에 캡슐화하게 되며, 브라우저는 HTML 문서를 해석해서 트리 형태로 구조화, 계층화된 노드들을 가지고 있는
DOM을 생성한다. DOM목적: Javascript를 사용해서 HTML을 조작하기 위한 인터페이스를 제공

- 💛
DOM을 이루는 모든 객체들은Node객체로부터 상속 받는다.
2. 노드의 유형 (nodeType)
- HTML 문서를 다룰 때 마주치게 되는 일반적인 노드 유형이다.
for (var key in Node) {
console.log(key, Node[key]);
}
// ELEMENT_NODE 1
// ATTRIBUTE_NODE 2
// TEXT_NODE 3
// CDATA_SECTION_NODE 4
// ENTITY_REFERENCE_NODE 5
// ENTITY_NODE 6
// PROCESSING_INSTRUCTION_NODE 7
// COMMENT_NODE 8
// DOCUMENT_NODE 9
// DOCUMENT_TYPE_NODE 10
// DOCUMENT_FRAGMENT_NODE 11
// NOTATION_NODE 12
// DOCUMENT_POSITION_DISCONNECTED 1
// DOCUMENT_POSITION_PRECEDING 2
// DOCUMENT_POSITION_FOLLOWING 4
// DOCUMENT_POSITION_CONTAINS 8
// DOCUMENT_POSITION_CONTAINED_BY 16
// DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC 32
- 모두 대문자이며
_로 단어를 구분한다.
| 숫자코드 | nodeType | 인터페이스/생성자 | 설명 |
|---|---|---|---|
| 1 | ELEMENT_NODE | HTML*ELEMENT, HTMLBodyElement, <body>, <a>, <p>, <script>, <style>, <html>, <h1> | 속성 노드를 가질 수 있는 유일한 노드 |
| 2 | ATTRIBUTE_NODE | class = "active" | 모든 HTML요소의 속성은 속성 노드이며 엘리먼트 노드에 대한 정보를 가진다. 해당 요소 노드의 자식노드에는 포함되지 않는다. |
| 3 | TEXT_NODE | Text(), html 문서 내의 텍스트 문자 | |
| 9 | DOCUMENT_NODE | window.document, HTMLDocument() | HTML 문서 전체를 나타내는 노드 |
| 10 | DOCUMENT_TYPE_NODE | <!DOCTYPE HTML>, DocumentType() | |
| 11 | DOCUMENT_FRAGMENT_NODE | document.createDocumentFragment() |
3. Node를 상속받은 하위 노드
- DOM 트리의 모든 노드들은
Node로 부터 속성과 메서드를 상속받는다.HTMLDocument>Document>Node>ObjectHTMLElement>Element>Node>ObjectText>CharacterData>Node>ObjectDocumentFragment>Node>Object
Node도Javascript생성자 함수이기 때문에 다른 객체들 처럼Object.prototype를 상속받는다.
4. Node의 다양한 속성 및 메서드
Node.property
Node.childNodesNode.firstChildNode.lastChildNode.nextSiblingNode.nodeNameNode.nodeTypeNode.nodeValueNode.parentNodeNode.previousSibling
Node.method()
Node.appendChild()Node.cloneNode()Node.compareDocumentPosition()Node.contains()Node.hasChildNodes()Node.insertBefore()Node.isEqualNode()Node.removeChild()Node.replaceChild()
하위 노드 인터페이스에서도 다양한 속성 및 메서드가 존재한다.
Document.method()
document.createElement()document.createTextNode()
HTML*Element.property
innerHTMLouterHTMLtextContentinnerTextouterTextfirstElementChildlastElementChildnextElemmentChildpreviousElementChildchildren
HTMLElement.method()
insertAdjacentHTML()
5. 노드의 유형, 이름 식별
- 모든 노드는
Node로 부터 상속받는nodeTypenodeName속성을 가진다.
document.querySelector('a').nodeType // 1 Node.ELEMENT_NODE
document.querySelector('a').nodeName // A
6. 노드 값 가져오기
nodeValue속성은 대부분 노드 유형에서는null값을 가져온다.- 이 속성의 용도는
Text와Comment노드에서 실제 텍스트 문자열을 추출하는데 초점을 맞추고 있다.
<a href="#">Hi</a>
document.doctype.nodeValue // null
document.querySelector('a').nodeValue // null
document.querySelector('a').firstChild.nodeValue // Hi
7,8. 노드 생성하기
- 브라우저는 HTML문서를 초기 로딩할 때 노드를 생성을 처리한다.
- 하지만
DOM API를 이용하면, HTML 로딩 이후에도 노드를 생성할 수 있다.
1) 메서드로 만들기
createElement()createTextNode()createAttribute()createComment()
document.createElement('div')
// <div></div>
document.createTextNode('Hi')
// "HI"
2) 문자열로 만들기
innerHTMLouterHTMLtextContentinsertAdjacentHTML()
<div id="A"></div>
<div id="B"></div>
<span id="C"></span>
<div id="D"></div>
<div id="E"></div>
document.getElementByID('A').innerHTML = '<strong>Hi</strong>'
document.getElementByID('B').outerHTML = '<div id="B" class="new">Da-ran!</div>'
document.getElementByID('C').textContent = 'dude'
document.getElementByID('D').innerText = 'Keep It!'
document.getElementByID('E').outerText = 'real!'
outer속성은 선택한 요소에 마크업을 새로 쓴다.
<div id="A"><strong>Hi</strong></div>
<div id="B" class="new">Da-ran!</div>
<span id="C">dude</span>
<div id="D">Keep It!</div> real!
3) innerHTML vs innerText vs textContent
innerHTML
innerHTML: 무거운 HTML파서를 호출하기에, 텍스트 노드만 생성하는 경우,textContent사용을 권장한다.innerHTML: 문자열 내에서 발견된 HTML요소를 실제 DOM노드로 변환textContent: 텍스트 노드로만 생성
innerText (비표준)
innerText- 문서 내 노드들의 레이아웃, 포지션을 재계산 후 다시 뿌려주는
Reflow가 발생 innerText는 스타일을 알고 있기 때문에, 숨겨진 요소들의 텍스트는 반환하지 않음innerText는 텍스트를 정규화해서 반환, 공백, 줄바꿈, 개행문자 포함XHTMLElement에 정의되어 있다.
- 문서 내 노드들의 레이아웃, 포지션을 재계산 후 다시 뿌려주는
textContent (DOM 사양)
textContent<script>,<style>을 비롯한 모든 요소의 내용을 가져옴- 문서 내에 있는 것을 마크업만 제거해서 그대로 반환하기 때문에 공백, 줄바꿈 개행문자도 포함
- 모든
Node에 정의되어 있다.
<span>Hello
<span style="display: none;">World</span>
</span>
innerText // Hello
textContent // Hello World
4) textContent vs value
innerText: 엘리먼트의 텍스트 노드value:input,textarea등의value값
Tab을 눌렀을 때 공백 추가하기
codeDOM.addEventListener("keydown",(e) => {
if(e.key === 'Tab') {
e.preventDefault();
codeDOM.value += ' ';
// codeDOM.textContent += ' '; ❌
}
});
5) document.write()
write()으로 전달된 값은 페이지가 로딩 및 해석되는 동안 페이지에 출력되기 때문에 로딩된 HTML문서가 해석 되는것을 지연/차단시키게 된다.
6) .insertAdjacentHTML()
Element노드에서만 작동- 시작 태그의 앞, 뒤, 종료 태그의 앞, 뒤 태그에 노드를 삽입할 수 있다.
<i id="elm"></i>
var elm = document.getElementById('elm')
dle.insertAdjacentHTML('beforebegin','<div>')
dle.insertAdjacentHTML('afterbegin','<span>dude-</span>')
dle.insertAdjacentHTML('beforeend','<span>-are</span>')
dle.insertAdjacentHTML('afterend','</div>')
<div><span>dude-</span><i id="elm"></i><span>-are</span></div>
beforebegin,afterend옵션은 노드가 DOM 트리 내에 존재하고 부모 요소를 가 가진 경우에만 동작한다.
9. DOM 트리를 Javascript 문자열로 추출하기
innerHTML,outerHTML,textContent- DOM에 노드를 생성하고 추가하는 데 사용하는 속성들이
Javascript문자열로도 추출할 수 있다.
console.log(document.getElementByID('A').innerHTML);
// <i>Hi</i>
console.log(document.getElementByID('A').innerText);
// Dude!
console.log(document.getElementByID('A').textContent);
// Dude!
10. 노드를 DOM에 추가하기
appendChild(): 호출된 노드의 자식 노드 끝에 삽입insertBefore(넣을 것, 어디다): 삽입 위치를 조정할 때 사용어디다인자를 생략하면appendChild()처럼 작동
<body>
<p>Hi</p>
</body>
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>
<ul>
<li>2</li>
<li>3</li>
</ul>
var text1 = document.createTextNode('1')
var li = document.createElement('li')
li.appendChild(text1)
var ul = document.querySelector('ul')
ul.insertBefore(li,ul,firstChild)
// <ul>
// <li>1</li>
// <li>2</li>
// <li>3</li>
// </ul>
11. 노드 제거하기 / 바꾸기
removeChild(),replaceChild()- 해당 노드를 반환
parentNode속성을 이용하여 부모 노드에 대한 접근을 얻어야함
divA.parentNode.removeChild(divA)
divA.parentNode.replaceChild(newSpan,divA)
- 해당 노드를 삭제하는 것이 아니라, 해당 돔트리와의 연결을 해제시켜 문서의 범위를 벗어나게 만들기만 한다. 따라서 해당 노드에 대한 메모리상의 참조는 여전히 가지게 된다.
innerHTML,outerHTML,textContent속성에 빈 문자열을 주는 쉽고 빠른 방법도 있지만, 실제로 노드를 메모리상에서 삭제하는 것이 아니기 때문에 브라우저 메모리 누수가 발생할 수 있다.
12. 노드 복제하기
Node.cloneNode(): 단일 노드 복제Node.cloneNode(true): 하위 자식 노드까지 모두 복제Element반환
<ul>
<li>Hi</li>
<li>There!</li>
</ul>
var cloneUl = document.querySelector('ul').cloneNode();
cloneUl.innerHTML // ul만 복제되었기 때문에 빈 문자열이 출력
cloneUl // <ul></ul>
var cloneUl = document.querySelector('ul').cloneNode(true);
cloneUl.innerHTML // <li>Hi</li><li>There!</li>
cloneUl //
- 노드 복제 시, 모든 특성 및 값도 복제된다.
addEventListener,node.onclick으로 추가된 것은 복제되지 않는다.
16. DOM 내의 노드 탐색하기
- 현재 노드와 관련있는 다른 노드에 대한 정보를 얻을 수 있다.
parentNodefirstChildlastChildnextSiblingpreviousSibling
<body>
<ul><!-- comment -->
<li id="A"></li>
<li id="B"></li>
<!-- comment -->
</ul>
</body>
var ul = document.querySelector("ul")
ul.parentNode.nodeName // body
ul.firstChild.nodeName // comment
ul.lastChild.nodeName // text (줄바꿈)
ul.querySelector('#A').nextSibling.nodeName
ul.querySelector('#B').previousSibling.nodeName
// text
text와 comment 노드를 무시하고 DOM 탐색하기
firstElementChildlastElementChildnextElementSiblingpreviousElementSiblingchildrenparentElement
var ul = document.querySelector("ul")
ul.firstElementChild.nodeName
ul.lastElementChild.nodeName
// li
ul.querySelector('#A').nextElementSibling.nodeName
ul.querySelector('#B').previousElementSibling.nodeName
// li
ul.children
// HTMLCollection
// 자식 노드는 text노드를 가짐
ul.firstElementChild.parentElement
// uㅣ
17. DOM트리 내의 Node위치 확인하기
Node.contains(): 특정 노드가 다른 노드를 포함하고 있는지 확인
document.querySelector('html').contains(document.querySelector('body'))
// true
//<html> 안에 <body>가 있다
compareDocumentPosition(): DOM 트리 내에서 주변 노드와 연관된 노드 위치가 담킨 코드를 반환한다.
| 반환코드 | 의미 |
|---|---|
| 0 | 동일 Element |
| 1 | DOCUMENT_POSITION_DISCONNECTED 선택된 노드와 전달된 노드가 동일한 문서에 존재하지 않음. |
| 2 | DOCUMENT_POSITION_PRECEDING 전달된 노드가 선택된 노드 앞에 있음. |
| 4 | DOCUMENT_POSITION_FOLLOWING 전달된 노드가 선택된 노드 뒤에 있음. |
| 8 | DOCUMENT_POSITION_CONTAINS 전달된 노드가 선택된 노드의 조상임. |
| 16,10 | DOCUMENT_POSITION_CONTAINED_BY 전달된 노드가 선택된 노드의 자손임. |
- 숫자코드는 특정 노드가 다른 노드와 하나 이상의 관계를 가질 수 있다.
- 노드가 포함 관계(16)이자, 앞에 있는 경우(4)는 16+4=20을 반환한다.
18. 두 노드가 동일한지 판단하기
Node.isEqualNode(): 매개변수로 전달하는 노드와 동일한지 확인
두 노드의 동일 조건
nodeName,localName,namespaceURI,prefix,nodeValue문자열 특성이 동일해야한다.NameNodeMaps특성이 동일하다.- 둘 다 null이거나 길이가 동일해야 하며, 하나의 맵 내에 존재하는 각 노드들과 다른 맵에 존재하는 노드가 동일해야 하되 인덱스가 동일할 필요는 없다.
childNodesNodeLists가동일해야한다.- 정규화가 동일성에 영향을 미칠 수 있으므로 비교 수행 전에 노드를 정규화해야한다.
<input type="text">
<input type="text">
<textarea>foo</textarea>
<textarea>bar</textarea>
var input = document.querySelectorAll('input');
input[0].isEqualNode(input[1]) //true
var textarea = document.querySelectorAll('textarea');
textarea[0].isEqualNode(textarea[1]) // false
- 두 노드가 동일한 노드를 참조하고 있는지 알고 싶다면
===연산자를 사용한다.