브라우저의 렌더링 엔진은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 자료구조인 DOM을 생성한다. DOM(Document Object Model)은 HTML 문서의 계층적 구조와 정보를 표현하면 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료구조다.
39.1 노드
39.1.1 HTML 요소와 노드 객체
HTML 요소 HTML element는 HTML 문서를 구성하는 개별적인 요소를 의미한다.
<div class = "greeting">hello</div>
<div> 시작 태그(start tag)
class 어트리뷰트 이름(attribute name)
"greeting" 어트리뷰트 값(attribute value)
Hello 콘텐츠(content)
</div> 종료 태그(end tag)
HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다. 이때 HTML 요소의 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 콘텐츠는 텍스트 노드로 변환된다.
HTML 문서는 HTML 요소들의 집합으로 이뤄지며, HTML 요소는 중첩 관계를 갖는다.
HTML 요소 간에는 중첩 관계에 의해 계층적인 부자parent-child 관계가 형성된다. 이러한 HTML 요소 간의 부자 관계를 반영하여 HTML 문서의 구성 요소인 HTML 요소를 객체화한 모든 노드 객체들을 트리 자료구조로 구성한다.
노드 객체들로 구성된 트리 자료구조를 DOM이라 한다. 노드 객체의 트리르 구조화되어 있기 때문에 DOM을 DOM 트리라고 부르기도 한다.
39.1.2 노드 객체의 타입
렌더링 엔진은 HTML 문서를 파싱하여 DOM을 생성한다.
노드 객체는 총 12개의 종류(노드 타입)가 있다. 이 중에서 중요한 노드 타입은 다음과 같이 4가지다.
- 문서노드 document node
- 요소 노드 element node
- 어트리뷰트 노드 attribute node
- 텍스트 노드 text node
39.1.3 노드 객체의 상속 구조
노드 객체도 자바스크립트 객체이므로 프로토타입에 의한 상속 구조를 갖는다.
모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받는다
*노드 객체의 상속 구조는 개발자 도구의 Elements 패널 우척의 Properties 패널에서 확인할 수 있다.
39.2. 요소 노드 취득
39.2.1 id를 이용한 요소 노드 취득
Document.prototype.getElementById 메서드는 인수로 전달된 id 어트리뷰트 값(이하 id 값)을 갖는 하나의 요소 노드를 탐색하여 반환한다. getElementById 메서드는 Document.prototype의 프로퍼티다. 따라서 반드시 문서 노드인 document를 통해 호출해야 한다.
<!DOCTYPE html>
<html>
<body>
<ul>
<li id="apple">Apple</li>
<li id="banana">Banana</li>
<li id="orange">Orange</li>
</ul>
<script>
//id 값이 'banana'인 요소 노드를 탐색하여 반환한다.
//두 번째 li 요소가 파싱되어 생성된 요소 노드가 반환된다.
const $elem = document.getElementById('banana');
//취득한 요소 노드의 style.color 프로퍼티 값을 변경한다
$elem.style.color = 'red';
</script>
</body>
</html>
- id 값은 HTML 문서 내에서 유일한 값이어야 한다.
- 공백 문자로 구분하여 여러 개의 값을 가질 수 없다
- 중복된 id 값을 갖는 요소가 여러 개 존재할 수 있으며 에러 발생 대신 id 값을 갖는 첫 번째 요소 노드만 반환한다.
- 인수로 전달된 id 값을 갖는 HTML 요소가 존재하지 않는 경우 getElementById 메서드는 null을 반환한다.
HTML 요소에 id 어트리뷰티를 부여하면 id 값과 동일한 이름의 전역 변수가 암묵적으로 선언되고 해당 노드 객체가 할당되는 부수 효과가 있다.
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script>
//id 값과 동일한 이름의 전역 변수가 암묵적으로 선언되고 해당 노드 객체가 할당된다.
console.log(foo === document.getElementById('foo')); //true
//암묵적 전역으로 생성된 전역 프로퍼티는 삭제되지만 전역 변수는 삭제되지 않는다.
delete foo;
console.log(foo); //<div id="foo"></div>
</script>
</body>
</html>
단, id 값과 동일한 이름의 전역 변수가 이미 선언되어 있으면 이 전역 변수에 노드 객체가 재할당되지 않는다.
39.2.2 태그 이름을 이용한 요소 노드 취득
Document.prototype/Element.prototype.getElementByTagName 메서드는 인수로 전달한 태그 이름을 갖는 모든 요소들을 탐 색하여 반환한다.
getElementByTagName 메서드는 여러 개의 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.
<!DOCTYPE html>
<html>
<body>
<ul>
<li id="apple">Apple</li>
<li id="banana">Banana</li>
<li id="orange">Orange</li>
</ul>
<script>
//태그 이름이 li인 요소 노드를 모두 탐색하여 반환한다.
//탐색된 요소 노드들은 HTMLCollection 객체에 담겨 반환된다.
//HTMLCollection 객체는 유사 배열 객체이면서 이터러블이다.
const $elems = document.getElementByTagName('li');
//취득한 모든 요소 노드의 style.color 프로퍼티 값을 변경한다.
//HTMLCollection 객체를 배열로 변환하여 순회하며 color 프로퍼티 값을 변경한다.
[...$elems].forEach(elem => { elem.style.color = 'red'; });
</script>
</body>
</html>
- getElementByTagName 메서드가 반환하는 DOM 컬렉션 객체인 HTMLCollection 객체는 유사 배열 객체이면서 이터러블이다.
- HTML 문서의 모든 요소 노드를 취득하려면 getElementByTagName 메서드의 인수로 ' * '를 전달한다.
- Document.prototype. getElementByTagName 메서드는 document를 통해 호출하며 DOM 전체에서 요소 노드를 탐색하여 반환한다.(getElementByClassName도 동일)
- Element. prototype. getElementByTagName 메서드는 특정 요소 노드를 통해 호출하며, 특정 요소 노드의 자손 노드 중에서 요소 노드를 탐색하여 반환한다.(getElementByClassName도 동일)
39.2.3 class를 이용한 요소 노드 취득
Document.prototype/Element.prototype.getElementByClassName 메서드는 인수로 전달한 class 어트리뷰트 값(이하 class값)을 갖는 모든 요소 노드들을 탐색하여 반환한다. 인수로 전달할 class 값은 공백으로 구분하여 어러 개의 class를 지정할 수 있다. getElementByClassName 메서드는 여러 개의 요소 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.
<!DOCTYPE html>
<html>
<body>
<ul>
<li class="fruit apple">Apple</li>
<li class="fruit banana">Banana</li>
<li class="fruit orange">Orange</li>
</ul>
<script>
//class 값이 'fruit'인 요소 노드를 모두 탐색하여 HTMLCollection 객체에 담아 반환한다.
const $elems = document.getElementByClassName('fruit');
//취득한 모든 요소의 CSS color 프로퍼티 값을 변경한다.
[...$elems].forEach(elem => { elem.style.color = 'red'; });
//calss 값이 'fruit apple'인 요소 노드를 모두 탐색하여 HTMLCollection 객체에 담아 반환한다.
const $apples = document.getElementByClassName('fruit apple');
//취득한 모든 요소 노드의 style.color 프로퍼티 값을 변경한다.
[...$apples].forEach(elem => { elem.style.color = 'blue'; });
</script>
</body>
</html>
39.2.4 CSS 선택자를 이용한 요소 노드 취득
CSS 선택자selector는 스타일을 적용하고자 하는 HTML 요소를 특정할 때 사용하는 문법이다.
/* 전체 선택자: 모든 요소를 선택 */
* { ... }
/* 태그 선택자: 모든 p 태그 요소를 모두 선택 */
p { ... }
/* id 선택자: id 값이 'foo'인 요소를 모두 선택 */
#foo { ... }
/* class 선택자: class 값이 'foo'인 요소를 모두 선택 */
.foo { ... }
/* 어트리뷰트 선택자: input 요소 중에 type 어트리뷰트 값이 'text'인 요소를 모두 선택 */
input[type=text] { ... }
/* 후손 선택자: div 요소의 후손 요소 중 p 요소를 모두 선택 */
div p { ... }
/* 자식 선택자: div 요소의 자식 요소 중 p 요소를 모두 선택 */
div > p { ... }
/* 인접 형제 선택자: p 요소의 형제 요소 중에 p 요소 바로 뒤에 위치하는 ul 요소를 선택 */
p + ul { ... }
/* 일반 형제 선택자: p 요소의 형제 요소 중에 p 요소 뒤에 위치하는 ul 요소를 모두 선택 */
p ~ ul { ... }
/* 가상 클래스 선택자: hover 상태인 a 요소를 모두 선택 */
a:hover { ... }
/* 가상 요소 선택자: p 요소의 콘텐츠 앞에 위치하는 공간을 선택
일반적으로 content 프로퍼티와 함께 사용된다.*/
p::before { ... }
- Document.prototype/Element.prototype.querySelector 메서드는 인수로 전달한 CSS 선택자를 만족시키는 하나의 요소 노드를 탐색하여 반환한다.
39.2.5 특정 요소 노드를 취득할 수 있는지 확인
Element.prototype.matches 메서드는 인수로 전달한 CSS 선택자를 통해 특정 요소 노드를 취득할 수 있는지 확인한다.
39.2.6 HTMLCollection과 NodeList
DOM 컬렉션 객체인 HTMLCollection과 NodeList는 DOM API가 여러 개의 결과값을 반환하기 위한 DOM 컬렉션 객체다.
HTMLCollection과 NodeList의 중요한 특징은 노드 객체의 상태 변화를 실시간으로 반영하는 살아있는 객체라는 것이다.
*for 문 순회 시 역방향으로 순회 또는 노드 객체가 남아 있지 않을 때 까지 무한 반복
//배열로 변환하여 순회
[...$elems].forEach(elem => elem.className = 'blue');
39.3 노드 탐색
DOM 트리 상의 노드를 탐색할 수 있도록 Node, Element 인터페이스는 트리 탐색 프로퍼티를 제공한다.
39.3.1 공백 텍스트 노드
HTML 요소 사이의 스페이스, 탭, 줄바꿈 등의 공백 문자는 텍스트 노드를 생성한다. 이를 공백 텍스트 노드라 한다.
39.3.2 자식 노드 탐색
자식 노드를 탐색하기 위해서는 탐색 프로퍼티를 사용한다.
39.3.3 자식 노드 존재 확인
자식 노드가 존재하는지 확인하려면 Node.prototype.hasChildNodes 메서드를 사용한다. hasChildNodes 메서드는 자식 노드가 존재하면 ture, 존재하지 않으면 false를 반환한다.
39.3.4 요소 노드의 텍스트 노드 탐색
firstChild 프로퍼티는 첫 번째 자식 노드를 반환한다.
39.3.5 부모 노드 탐색
부모 노드를 탐색하려면 Node.prototype.parentNode 프로퍼티를 사용한다.
39.3.6 형제 노드 탐색
부모 노드가 같은 형제 노드를 탐색하기 위해서는 탐색 프로퍼티를 사용한다.
출처 : 이웅모. 「모던 자바스크립트 Deep Dive」. 위키북스. 2023
'프로그래밍언어 > JavaScrpit' 카테고리의 다른 글
[모던 자바스크립트 Deep Dive] 42장 비동기 프로그래밍 (0) | 2024.02.18 |
---|---|
[모던 자바스크립트 Deep Dive] 39장 DOM(2) (0) | 2024.02.17 |
[모던 자바스크립트 Deep Dive] 38장 브라우저의 렌더링 과정 (0) | 2024.01.14 |
[모던 자바스크립트 Deep Dive] 25장 클래스 (0) | 2023.09.14 |
[모던 자바스크립트 Deep Dive] 24장 클로저 (0) | 2023.08.29 |