본문 바로가기
Programming/JavaScript

[ 모던 자바스크립트 스터디 ] DOM

by 코뮤(commu) 2022. 11. 3.
728x90
반응형

브라우저의 렌더링 엔진은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 자료구조인 DOM을 생성한다.

DOM은 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API,

즉 프로퍼티와 메서드를 제공하는 트리 자료구조다.

 

노드

 

HTML 요소와 노드 객체

HTML 요소는 HTML 문서를 구성하는 개별적인 요소를 의미한다.

HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다.

이때 HTML 요소의 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 컨텐츠는 텍스트 노드로 변한다.

 

HTMl 요소간의 부자 관계를 반영해 HTML 요소를 객체화한 모든 노드 객체들을 트리 자료 구조로 구성한다.

 

 

트리자료구조

트리 자료구조는 노드들의 계층 구조로 이루어진다.

노드 객체들로 구성된 트리 자료구조를 DOM이라고 한다.

 

DOM은 노드 객체의 계층적인 구조로 구성된다.

노드 객체는 12가지의 종류가 있고 상속 구조를 갖는다.

이중 중요한 노드 타입은 4가지다.

 

 

문서노드

DOM 트리의 최상위 루트 노드로 document 객체를 가리킨다.

이는 브라우저가 렌더링한 HTML 문서 전체를 가리키는 객체로 전역객체 window의

document 프로퍼티에 바인딩되어있다.

 

요소노드

HTML 요소를 가리키는 객체다.

 

어트리뷰트 노드

HTML 요소의 어트리뷰트를 가리키는 객체다.

요소 노드는 부모노드와 연결되어 있지만, 어트리뷰트노드는 요소 노드에만 연결되어 있다.

 

 

텍스트 노드

HTML 요소의 텍스트를 가리키는 객체다.

자식 노드를 가질 수 없는 leaf node 이기에 DOM 트리의 최종단이다.

 

 

노드 객체의 상속 구조

 

DOM을 구성하는 노드객체는 표준 빌트인 객체가 아닌

브라우저 환경에서 추가적으로 제공하는 호스트 객체다.

하지만 노드 객체도 자바스크립트 객체므로 프로토타입에 의한 상속 구조를 갖는다.

 

모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받는다.

추가적으로 문서 노드는 Document, HTMLDocument 인터페이스를 상속받고

어트리뷰트 노드는 Attr, 텍스트 노드는 CharacterData 인터페이스를 각각 상속받는다.

요소 노드는 Element 인터페이스를 상속받는다.

 

이를 프로토타입 체인 관점에서 살펴보면,

input 요소를 파싱해 객체화한 input 요소 노드 객체는

HTMLInputElement, HTMLElement, Element, Node, EventTarget, Object 의

prototype에 바인딩 외어 있는 프로토타입 객체를 상속받는다.

 

노드 객체의 상속구조는 개발자 도구의 Elements 패널 우측 Properties 패널에서 확인 가능하다.

 

 

요소 노드 취득

 

id 이용하기

 

Document.prototype.getElementById 메서드를 이용한다.

인수로 전달한 id를 갖는 하나의 요소 노드를 탐색해 반환한다.

 

id 값은 HTML 문서 내에서 유일한 값이며 만약 중복될 경우

인수로 전달된 id 값을 갖는 첫번째 요소 노드만 반환한다.

만약 전달 받은 id 값을 갖는 요소가 존재하지 않으면 null 을 반환한다.

 

HTML 요소에 id 어트리뷰트를 부여하면 id 값과 동일한 이름의 전역 변수가 암묵적으로 선언되고

해당 노드 객체가 할당되는 부수효과가 있다.

단, id 값과 동일한 이름의 전역변수가 이미 있으면 전역 변수에 노드 객체가 재할당되지 않는다.

 

 

태그 이름 이용하기

 

Document.prototype/Element.prototype.getElementsByTagName 메서드는

인수로 전달한 태그 이름을 갖는 모든 요소 노드들을 탐색하여 반환한다.

 

해당 메서드는 여러 개의 요소 노드 객체를 갖는 DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.

해당 객체는 유사 배열 객체이자 이터러블이다.

 

<script>
	const $fruits = document.getElementById('fruits');
    const $lisFromFruits = $fruits.getElementsByTagName('li');
</script>

 

 

class 이용하기

 

Document.prototype/Element.prototype.getElementsByClassName 메서드를 이용한다.

인수로 전달한 class 값을 갖는 모든 요소 노드들을 탐색해 반환한다.

인수로 전달할 class 값은 공백으로 구분해 여러개의 class 지정도 가능하다.

얘도  DOM 컬렉션 객체인 HTMLCollection 객체를 반환한다.

 

 

CSS 선택자 이용하기

 

CSS selector 는 스타일을 적용하고자 하는 HTML 요소를 특정할 때 사용하는 문법이다.

 

/* 전체 선택자 */
* { ... }

/* 태그 선택자 */
p { ... }

/* id 선택자 */
#foo { ... }

/* class 선택자 */
.foo { ... }

/* 어트리뷰트 선택자 */
input[type=text] { ... }

/* 후손 선택자 */
div p { ... }

/* 자식 선택자 */
div > p { ... }

/* 인접 형제 선택자: p 요소 바로 뒤에 위치하는 ul 요소 선택 */
p + ul { ... }

/* 일반 형제 선택자: p 요소 뒤에 위치하는 ul 요소 모두 선택 */
p ~ ul { ... }

/* 가상 클래스 선택자 */
a:hover { ... }

/* 가상 요소 선택자 : p 요소 콘텐츠의 앞에 위치하는 공간 선택 */
p::before { ... }

 

Document.prototype/Element.prototype.querySelector 메서드는 인수로 전달한 CSS 선택자를

만족시키는 하나의 요소 노드를 탐색해 반환한다.

만족시키는 요소 노드가 여러개일 때는 첫번째 요소 노드만 반환한다.

 

Document.prototype/Element.prototype.querySelectorAll 메서드는

만족시키는 모든 요소 노드를 탐색해 반환한다.

여러 개의 노드 객체를 갖는 DOM 컬렉션 객체인 NodeList 객체를 반환한다.

 

CSS Selector 문법을 사용하는 querySelector, querySelectorAll 메서드는

위에 소개한 getElementId, getElementsBy*** 메서드보다는 느리다고 알려져있지만,

CSS Selector 문법을 사용하여 더 구체적인 조건으로 요소 노드를 취득할 수 있다는 장점이 있다.

 

책에서는 id 어트리뷰트가 있는 요소 노드를 취득하는 경우에는 getElementById 메서드를 사용하고,

그 외의 경우는 CSS Selector 문법을 사용하는 것을 권장하고 있다.

 

 

특정 요소 노드를 취득할 수 있는지 확인

 

Element.prototype.matches 메서드는 인수로 전달한 CSS 선택자를 통해

특정 요소 노드를 취득할 수 있는지 확인한다.

 

이는 이벤트 위임을 사용할 때 유용하다고 하는데, 자세한 사용법은 다음 포스팅에서 다루게될 것 같다.

 

 

노드 탐색

 

요소 노드를 취득한 다음, 취득한 요소 노드를 기점으로 DOM 트리의 노드를 옮겨 다니며

부모, 형제, 자식 노드 등을 탐색해야할 때가 있다.

 

parentNode, previousSibling, firstChild, childNodes 프로퍼티는

Node.prototype 이 제공하고,

previousElementSibling, nextElementSibling, children 프로퍼티는

Element.prototype이 제공한다.

 

노드 탐색 프로퍼티는 모두 접근자 프로퍼티다.

 

 

 

DOM 조작

 

새로운 노드를 생성해 DOM에 추가하거나 기존 노드를 삭제/교체하는 것을 말한다.

 

 

innerHTML

 

Element.prototype.innerHTML 프로퍼티는 setter 와 getter 모두 존재하는 접근자 프로퍼티다.

요소 노드의 innerHTML 프로퍼티에 할당한 HTML 마크업 문자열은 렌더링 엔진에 의해 파싱되어

요소 노드의 자식으로 DOM 에 반영된다.

 

이 경우 XSS 를 조심해야한다. (내 전문 영역,,,^~^)

 

HTML5는 innerHTML 프로퍼티로 삽입된 script 요소 내의 자바스크립트 코드를 실행하지 않는다.

 

HTML 새니티제이션

xss 공격을 예방하기 위해 잠재적 위험을 제거하는 기능을 말한다.

DOMPurify 라이브러리를 사용하길 권고한다.

 

 

 

 

insertAdjacentHTML 메서드

 

Element.prototype.insertAdjacentHTML(position, DOMString) 메서드는

기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입한다.

 

첫번째 인수로 전달할 수 있는 문자열은

 

'beforebegin', 'afterbegin', 'beforeend', 'afterend' 이렇게 4가지이다.

이 메서드는 기존 요소에는 영향을 안주고 새롭게 삽입할 요소만 파싱해 추가하므로

innerHTML 프로퍼티보다 효율적이고 빠르다.

 

 

728x90
반응형