8/ DOM(1) - 노드의 계층 구조(1)

8/ DOM(1) - 노드의 계층 구조(1)

‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
넘나 많은 프로퍼티와 메서드들 @_@


브라우저는 웹 문서(HTML, XML, SVG)를 로드한 후, 파싱하여 DOM(문서 객체 모델: Document Object Model)을 생성한다.

  • 텍스트 파일로 만들어져 있는 웹 문서를 브라우저에 렌더링하기 위해서는 웹 문서를 브라우저가 이해할 수 있는 구조로 메모리에 올려야 한다.

  • 브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 DOM이라 한다.

  • 즉 모든 요소와 요소의 어트리뷰트, 텍스트를 각각의 객체로 만들고 이들 객체를 부자 관계를 표현할 수 있는 트리 구조로 구성한 것이 DOM이다.

  • 이 DOM은 자바스크립트를 통해 동적으로 변경할 수 있으며 변경된 DOM은 렌더링에 반영된다.

  • 이러한 웹 문서의 동적 변경을 위해 DOM은 프로그래밍 언어가 자신에 접근하고 수정할 수 있는 방법을 제공하는데 일반적으로 프로퍼티와 메소드를 갖는 JavaScript 객체로 제공된다.

  • 이를 DOM API(Application Programming Interface)라고 부른다.

  • 달리 말하면 정적인 웹페이지에 접근하여 동적으로 웹페이지를 변경하기 위한 유일한 방법은 메모리 상에 존재하는 DOM을 변경하는 것이고, 이때 필요한 것이 DOM에 접근하고 변경하는 프로퍼티와 메소드의 집합인 DOM API이다.

DOM은 HTML, JavaScript에서 정의한 표준이 아닌 별개의 W3C의 공식 표준이며 플랫폼/프로그래밍 언어 중립적이다. DOM은 다음 두 가지 기능을 담당한다.


목차

  1. Node 타입
    • nodeName, nodeValue
      • 요소의 경우 nodeName은 태그명, nodeValue는 null
    • 노드 사이의 관계
      • ChildNodes / ParentNodes / firstChild / lastChild / hasChildNodes(), ownerDocument 프로퍼티
    • 노드 조작
      • appendChild() / insertBefore() / replaceChild() / removeChild()
    • 기타 메서드
      • cloneNode() / nomalize()
  2. Document 타입
    • Document 자식 노드
      • documentElement(=<html>)
    • 문서 정보
      • document.title / document.URL / document.domain / document.referrer
    • 요소 위치
      • getElementById() / getElementByTagName() (namedItem) / getElementByName()
    • 특별한 컬렉션
      • document.anchors / document.applets / document.forms / document.images / document.links
    • DOM 준수 탐지
      • hasFeature()
    • 문서에 쓰기
      • write() / writeIn() / open() / close()
  3. Element 타입
    • HTML 요소
      • id / title / lang / dir / className
    • 속성 얻기
      • getAttribute()
    • 속성 설정
      • setAttribute()
    • 속성 제거
      • removeAttribute()
    • attributes 프로퍼티
      • getNamedItem() / removeNamedItem(name) / setNamedItem(), item()
    • 요소 생성
      • createElement()
    • 요소의 자식

—- 2편 👇

  1. Text 타입
  2. Comment 타입
  3. CDATASection 타입
  4. DocumentType 타입
  5. DocumentFragment 타입
  6. Attr 타입


노드의 계층 구조

  • 문서 객체 모델 DOM은 HTML과 XML 문서에 대한 애플리케이션 프로그래밍 인터페이스이다. (api)
  • DOM은 문서를 노드의 계층 구조 트리로 표현한다.
  • 개발자는 이를 통해 페이지 각 부분을 추가, 제거, 수정한다.
  • 자바스크립트를 통해 HTML에 접근이 가능한 이유는 html이 document object model에 따라 기술되고 이 dom 인터페이스를 통해 기술된 html element가 객체로써 자바스크립트와 연결되기 때문에 접근이 가능한 것이다.

  • 노드 타입에는 여러 가지가 있으며 각 타입은 문서에서 서로 다른 정보나 마크업을 표현한다.
  • 노드 타입은 서로 다른 특징, 데이터, 메서드를 가지며 각 노드는 다른 노드와 관계가 있을 수 있다.
  • 특정 노드에 뿌리를 둔 트리 구조로 표현된다.
1
2
3
4
5
6
7
8
<html>
<head>
<title>Sample Pate</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
- 여기서 문서(Document) 노드가 루트이다. - 문서 요소 : 문서 노드의 자식. 여기서는 `` - 문서 하나에 문서 요소 하나만 있을 수 있다. - HTML페이지에서 문서요소는 항상 `` 요소이다. - 각 마크업은 트리에서 노드로 표현된다. - 총 12가지 노드 타입이 있으며 모든 노드틑 `기반 타입`(base type)을 상속한다.

1. Node 타입

  • DOM 레벨 1에는 Node라는 인터페이스가 있다.
  • DOM에 존재하는 노드 타입은 모두 이 인터페이스를 구현한다.
  • 모든 브라우저에서는 Node 타입에 접근할 수 있다.
  • 자바스크립트 노드 타입은 모두 Node를 상속하므로 모든 노드 타입에서 같은 기본 프로퍼티와 메서드를 고융한다.

모든 노드에는 타입을 나타내는 nodeType 프로퍼티가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
Node.ELEMENT_NODE (1)
Node.ATTRIBUTE_NODE (2)
Node.TEXT_NODE (3)
Node.CDATA_SECTION_NODE (4)
Node.ENTITY_REFERENCE_NODE (5)
Node.ENTITY_NODE (6)
Node.PROCESSING_INSTRUCTION_NODE (7)
Node.COMMENT_NODE (8)
Node.DOCUMENT_NODE (9)
Node.DOCUMENT_TYPE_NODE (10)
Node.DOCUMENT_FRAGMENT_NODE (11)
Node.NOTATION_NODE (12)
1
2
3
4
5
6
7
if (someNode.nodeType == Node.ELEMENT_NODE){
alert("Node is an element.")
} // IE에서는 오류

if (someNode.nodeType == 1){
alert("Node is an element.")
} // 모든 브라우저에서 동작

1-1. nodeName, nodeValue

  • nodeName과 nodeValue는 해당 노드의 정보를 제공한다.
  • 요소(element)의 nodeName은 요소의 태그명과 일치하고, nodeValue는 null이다.
  • 텍스트 노드일 경우 nodeValue는 문자열이다.

1-2. 노드 사이의 관계

1-2-1. ChildNodes 프로퍼티

NodeList가 저장된다.
  • 유사배열 객체

  • 노드를 순서 있는 목록으로 저장하여 위치 기반으로 접근 가능.

  • length 프로퍼티 : 호출 당시 노드리스트에 담긴 노드 숫자임을 기억하자.

  • Array의 인스턴스는 아니다.

  • DOM 구조의 쿼리 결과

  • 계속 바뀌므로 살아있는 객체라고도 부른다.

  • childNodes는 모든 자식요소 찾기

  • children은 모든 자식요소 찾기이지만 요소노드만 찾는다.

  • 노드 리스트에 저장된 노드를 접근하는 방법 (어느쪽을 더 권잔하진 않는다.)

    • 대괄호 표기법
    • item() 메서드
      1
      2
      3
      const firstChild = someNode.childNodes[0];
      const secondChild = someNode.childNodes.item(1);
      const count = someNode.childNodes.length;

1-2-2. parentNode 프로퍼티

  • childNodes 목록에 포함된 노드는 모두 부모가 같으므로 각각의 parentNode 프로퍼티는 같은 노드를 가리킨다.
  • childeNOdes 목록의 각 노드들은 형제관계이며 previousSiblingnextSibling 프로퍼티로 이동할 수 있다.
  • 자식 노드가 하나 뿐이라면 해당 노드의 nextSibling과 previousSibling은 모두 null이다.

1-2-3. firstChild 프로퍼티

childNodes 목록에서 첫번째 노드를 가리킨다.
someNode.firstChild = someNode.childNodes[0]

1-2-4. lastChild 프로퍼티

childNodes 목록에서 마지막 노드를 가리킨다.
someNode.lastChild = someNode.childNodes[someNode.childNodes.length-1]

1-2-5. hasChildNodes() 메서드

노드에 자식 노드가 있으면 true를 반환.
length로 자식 노드 확인하는 것보다 효과적.

1-2-6. ownerDocument 프로퍼티

전체 문서를 표현하는 문서 노드에 대한 포인터
노드 계층 구조를 따라 위로 거슬러 올라갈 필요 없이 문서 노드에 빠르게 접근 가능하다.


1-3. 노드 조작

  • 노드 사이의 관계 포인터는 모두 읽기 전용
  • 아래 4가지 메서드는 자식에서만 동작하므로 부모 노드를 정확히 알아야한다.

1-3-1. appendChild()

  • childNodes 목록 마지막에 노드를 추가한다.
  • 새로 추가한 노드, 부모 노드, childNodes 목록에 포함된 이전의 마지막 자식 노드에서 모든 관계 포인터가 업데이트 된다.
  • 이미 문서에 존재하고 있는 노드를 추가한다면, 해당 노드는 이전 위치에서 추가된 위치로 옮겨진다.

1-3-2. insertBefore(삽입할 노드, 기준 노드)

  • 삽입할 노드와 기준 노드 2가지를 매개변수로 받는다.
  • 삽입한 노드는 기준 노드의 이전형제가 되며, 이동이 끝나면 메서드는 삽입한 노드를 반환한다.

1-3-3. replaceChild(삽입할 노드, 교체할 노드)

  • 기존 노드를 교체한다.
  • 교체할 노드(B)에 있던 자리에 삽입할 노드(A)가 들어간다.
  • B의 관계 표인터는 모두 A에 복사한다.
    • B는 같은 문서 소유이긴 하지만 문서에서 위치를 지정받지 못한 채 붕 떠 있는 상태이다.

1-3-4. removeChild()

  • 제거할 노드 하나만 매개변수로 받는다.
  • 제거된 노드는 아직 해당 문서 소유이긴 하지만 문서에서 위치를 지정받지는 못했다.

1-4. 기타 메서드

1-4-1. cloneNode(boolean)

  • 자신을 호출한 노드의 복제본을 생성한다.
  • 매개변수로는 자손 노드까지 복제할지 나타내는 불리언이다.
    • true : 자손 노드 전체를 복제
    • false : 해당 노드 하나만 복제
  • 복제된 노드를 반환하는데, 이는 여전히 문서 소유이지만 부모 노드가 할당되지 않는다.
    • 고아노드라고 한다.
    • appendChild()나 insertBefore(), replaceChild()를 통해 문서에 추가하기 전에는 트리 안에 존재하지 않는다.
1
2
3
4
5
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
1
2
3
4
5
const deepList = myList.cloneNode(true) // myList에 ul요소에 대한 참조를 저장했다고 가정
console.log(deepList.childNodes.length) // 3 or 7(공백포함)

const shallowList = myList.cloneNode(false);
console.log(shallowList.childNodes.length) //0

1-4-2. nomalize()

  • 문서 서브트리에 존재하는 텍스트 노드를 다루는 것 뿐.
  • 파서의 구현 방식이나 DOM 조작 결과로 텍스트 없는 텍스트 노드가 생기거나 텍스트 노드끼리 형제 노드가 될 가능성이 있다.
  • nomalize를 호출하면 노드의 자손에서 이 두가지 상황이 생기지 않았는지 검색한다.
  • 빈 텍스트 노드를 찾으면 제거하고 텍스트 노드끼리 형제인 경우를 발견하면 두 노드를 하나로 합친다.


2. Document 타입

  • 자바스크립트는 문서 노드를 Document 타입으로 표현한다.
  • 브라우저에서 전체 HTML 페이지를 표현하는 문서 객체는 HTMLDocument의 인스턴스
  • HTMLDocument는 Document를 상속한다.
  • document 객체는 window의 프로퍼티이므로 전역에서 접근할 수 있다. window.document
  • Document 타입은 HTML 페이지 또는 XML 기반 문서를 표현한다.
  • document 객체를 통해 페이지에 대한 정보를 얻고 구조 및 외관을 조작한다.

Document 노드의 특징

  • nodeType은 9
  • nodeName은 “#document”
  • nodeValue는 null
  • parentNode는 null
  • ownerDocument는 null
  • 자식 노드로 DocumentType(최대 1개) Element(최대 1개), Processing Instruction, Comment를 가질 수 있다.

2-1. Document 자식 노드

Document 자식으로

  • DocumentType
  • Element
  • ProcessingInstruction
  • Comment

2-1-1. documentElement 프로퍼티

  • HTML페이지의 <html>요소를 가리킨다.

  • childNodes의 document 요소보다 documentElement프로퍼티가 해당 요소에 더 빨리, 더 직접적으로 접근한다.

    1
    2
    const html = document.documentElement;
    console.log(html === document.childNodes[0] === document.firstChild)
  • document 객체는 HTMLDocument의 인스턴스이므로 <body>요소를 직접적으로 가리키는 body 프로퍼티를 갖는다.

document 객체

2-1-2. DocumentType

<!DOCTYPE> 태그는 문서의 다른 부분과는 별도의 엔티티로 간주하며 포함된 정보는 다음과 같이 doctype 프로퍼티를 통해 접근할 수 있다.

1
const doctype = document.doctype

2-2. 문서 정보

  • document 객체는 HTMLDocument의 인스턴스이므로 표준 Document 객체에는 존재하지 않는 프로퍼티를 여럿 가진다.
  • 이들 프로퍼티는 현재 불러들인 웹 페이지에 대한 정보이다.

2-2-1. document.title

  • <title> 요소 텍스트가 들어있다.
  • 읽을 수도 있고 재설정도 가능하다.

2-2-2. 웹페이지 요청과 관련한 프로퍼티

HTTP 헤더에 들어있다.

  • URL : 페이지의 완전한 URL
  • domain : 페이지의 도메인 이름,
  • referrer : 이 페이지를 링크한 페이지의 URL. 없으면 빈 문자열

2-3. 요소 위치

특정 요소나 요소 그룹에 대한 참조를 얻는 일을 자주한다.
대표적인 2가지 메서드. getElementById(), getElementByTagName()

2-3-1. getElementById()

  • 찾으려는 요소 ID를 매개변수로 받고 해다 요소를 찾아 반환하며 그런 ID의 요소가 존재하지 않으면 null반환.
  • 소문자와 대문자를 구분해야한다.
  • 같은 요소가 2개 이상 존재하면 첫 번째 요소를 반환한다.
  • document.getElementBy~ : 단일 엘리먼트를 선택하는 메소드
  • document.getElementsBy~ : 다중 엘리먼트를 선택하는 메소드
    • 배열형태로 받아진다.

2-3-2. getElementByTagName()

  • 요소의 태그 이름을 매개변수로 받고 해당하는 요소가 담긴 NodeList를 반환한다.
    • HTML 문서에서는 HTMLCollection 객체를 반환한다.
- NodeList 객체와 마찬가지로 HTMLCollection 객체의 데이터 역시 대괄호기법과 item() 메서드로 접근 가능하다. - HTMLCollection의 `namedItem()` 메서드 - name 속성을 통해 컬렉션 데이터에 대한 참조를 얻는다.
1
<img src="myimage.jpg" name="myImage">
1
2
3
const images = document.getElementByTagName("img")
const myImage = images.namedItem("myImage")
const myImage = images["myImage"]
  • HTMLCollection 객체에서는 대괄호 표기법에
    • 숫자형 색인과 => item()사용
    • 문자형 색은을 모두 사용할 수 있다. => namedItme() 사용
    • 문서 전체는 아리테스크*를 사용한다.
      1
      const allElements = document.getElementByTagName("*")

2-3-4. getElementByName()

name 속성 값이 주어진 문자열에 일치하는 요소를 반환한다.

  • 라디오 버튼에 자주 사용한다.
  • id 속성은 label요소와 연결하는 역할을 하며
  • name 속석은 값을 서버에 보낼 때 이중 단 하나만 보내는 역할을 한다. (체크된)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <fieldset>
    <legend>Which color do you prefer?</legend>
    <ul>
    <li>
    <input type="radio" value="red" name="color" id="colorRed">
    <label for="colorRed">Red</label>
    </li>
    <li>
    <input type="radio" value="green" name="color" id="colorGreen">
    <label for="colorGreen">Green</label>
    </li>
    <li>
    <input type="radio" value="white" name="color" id="colorBlue">
    <label for="colorBlue">Blue</label>
    </li>
    </ul>
    </fieldset>

2-4. 특별한 컬렉션

document객체에는 특별하 컬렉션이 몇가지 있다.
각 컬렉션은 모두 HTML Collection 객체이고,
문서에 공통된 요소들에 빠르게 접근할 수 있도록 만들어졌다.

  • document.anchors : name속성이 있는 <a> 요소를 모두 갖고온다.
  • (폐기)document.applets : <applet> 요소를 모두 갖고온다.
  • document.forms : <form> 요소를 모두 가져온다. (document.getElementsByTagName(“form”)과 같다.)
  • document.images : <img> 요소를 모두 갖고온다.
  • document.links : href속성이 있는 <a>요소를 모두 가져온다.

2-5. DOM 준수 탐지

hasFeature()


2-6. 문서에 쓰기

write() : 넘겨 받은 텍스트를 그대로 추가하고
writeIn() : 줄바꿈을 문자(\n)를 문자열 마지막에 추가한다.
open() : 페이지 스트림을 열고
close() : 페이지 스트림을 닫습니다.



3. Element 타입

Element 요소의 특징

  • nodeType은 1이다.
  • nodeName은 요소의 태그 이름이다.
  • nodeValue는 null이다.
  • parentNode는 Document 또는 Element이다.
  • 자식노드로 Element나 Text, Comment, ProcessingInstruction, CDATASection, EntityReference를 가질 수 있다.

3-1. HTML 요소

HTMLElement 타입을 통해 표현된다.
HTMLElement는 Element를 직접적으로 상속한다.

id : 요소의 고유한 식별자
title : 요소에 대한 추가 정보, 일반적으로 툴팁으로 표현됨
lang : 요소 콘텐츠의 언어 코드. 거의 사용되지 않는다.
dir : 언어의 표기 반향. ltr은 왼쪽 => 오른쪽, rtl은 오른쪽 => 왼쪽. 거의 사용되지 않는다.
className : CSS 클래스인 class 속성을 나타낸다. class가 ECMAScript의 예약어이기 때문에 className이라고 사용한다.

1
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>

3-2. 속성 얻기 (getAttribute())

getAttribute(속성이름) : 공식 속성 이외에 커스텀 속성을 가져오는데도 쓸 수 있다.
setAttribute(속성이름, 속성이름의 값)
removeAttribute(속성이름)

  • 속성이름은 대소문자를 구분하지 않는다.
  • HTML5 명세에서는 커스텀 속성 앞에 전치사 data-를 붙여야 유효한 것으로 인정한다.
  • getAttribute(“style”)은 객체를 반환, getAttribute(“onclick”)은 함수를 반환한다.
  • 위의 속성과 차이점때문에 개발자들은 getAttribute()는 거의 사용하지 않고 객체 프로퍼티를 사용한다.
  • getAttribute() 메서드는 주로 커스텀 속성의 값을 가져올 때 사용하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var four = document.getElementById('four');

// class 어트리뷰트가 존재하지 않으면
if (!four.hasAttribute('class')) {
// four에 class 어트리뷰트를 추가하고 값으로 'white'를 설정
four.setAttribute('class', 'white');
} else { // four에 class 어트리뷰트가 존재하면
four.className = 'white';
}

// class 어트리뷰트의 값을 취득
console.log(four.getAttribute('class')); // white

// class 어트리뷰트를 제거
four.removeAttribute('class');

// class 어트리뷰트의 존재를 확인
console.log(four.hasAttribute('class')); // false

3-3. 속성 설정 (setAttribute())

  • 속성 이름과 설정할 값 두가지를 매개변수로 받는다.
  • 해당 속성이 존재하지 않으면 솏어을 새로 생성하고 값을 설정한다.
  • 속성 이름은 소문자로 통일된다.

3-4. 속성 제거 (removeAttribute())

  • 속성의 값만 지우는 것이 아니라 요소에서 속성을 완전히 제거한다.
  • 자주 쓰이지는 않는다.

3-5. attributes 프로퍼티

  • Element 타입은 DOM 노드 타입 중에서 attributes 프로퍼티를 갖는 유일한 타입이다.
  • attributes 프로퍼티에는 NodeList처럼 살아있는 컬렉션 NamedNodeMap이 저장된다.
  • 요소 속성은 모두 Attr 노드로 표현되며 각 Attr노드는 NamedNodeMap 객체에 저장된다.
  • attributes 프로퍼티 안의 각 노드는
    • nodeName이 속성 이름
    • nodeValue는 속성 값
  • 보통은 아래 메서드들 보다는 getAttribute(), removeAttribute(), setAttribute() 메서드가 더 많이 사용된다.

NamedNodeMap 객체의 메서드들

  • getNamedItem(name) : nodeName 프로퍼티가 name인 노드를 반환한다.
  • removeNamedItem(name) : nodeName 프로퍼티가 name인 노드를 목록에서 제거한다.
  • setNamedItem(node) : node를 목록에 추가하고 nodeName 프로퍼티에 따라 색인한다.
  • item(pos) : 인덱스가 pos인 노드를 반환한다.

attributes 메서드들이 유용한 경우는 요소의 속성을 대상으로 루프가 필요할 때.
각 속성의 이름과 값을 문자열에 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function outputAttributes(element) {
const pairs = new Array(),
attrName,
attrValue,
i,
len;

for (i = 0, len = element.attributes.length.length; i < len; i++) {
attrName = element.attributes[i].nodeName;
attrValue = element.attributes[i].nodeValue;
pairs.push(attrName + "=\"" + attrValue + "\"");
}
return pairs.join(" ");
}

3-6. 요소 생성 (document.createElement())

- createElement() 메서드는 새 요소를 생성하고 ownerDocument 프로퍼티를 설정한다. - 생성 이후에는 문서 트리의 일부가 아니므로 appendChild(), insertBefore(), replaceChild() 메서드를 통해 요소를 문서 트리에 추가해야한다. - IE7이전 버전에는 HTML을 통으로 인자로 넘길 수 있다.

3-7. 요소의 자식

  • 요소는 자식 요소나 자손 요소를 가질 수 있고, 그 숫자는 제한이 없다.

    1
    2
    3
    4
    5
    <ul id="myList">
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    </ul>
  • <ul>요소 자식 노드가 7개 생긴다.

    • <li>는 3개, <text> 4개 (<li>와 텍스트 사이의 공백)

참고링크

  1. http://poiemaweb.com/js-dom
  2. http://webclub.tistory.com/339

생소했던 단어

  1. MIME타입
  2. Gecko