본문 바로가기

JavaScript

[모던자바스크립트-DeepDive]39장 DOM

 본 글은 자바스크립트 스터디를 진행하면서 [모던자바스크립트 DeepDive] 책을 바탕으로 작성된 글입니다.

 

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

DOM 은 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료 구조이다

 

 

노드

📙 HTML 요소와 노드 객체

HTML 요소는

  • HTML 문서를 구성하는 개별적인 요소를 의미한다
  • 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다
  • 이때, HTML 요소의 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 컨텍츠는 텍스트 노드로 변한다

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

 

 

 

📙 트리 자료 구조

트리 자료 구조는

  • 노드들의 계층 구조로 이루어진다
  • 노드 객체들로 구성된 트리 자료구조를 DOM 이라고 한다

 

DOM은 

  • 노드 객체의 계층적인 구조로 구성된다
  • 노드 객체는 12가지의 종류가 있고 상속 구조를 갖는다
  • 이중 중요한 노드 타입은 4가지다

1️⃣ 문서노드

  • DOM 트리의 최상위 루트 노드로 document 객체를 가리킨다
  • 이는 브라우저가 렌더링한 HTML 문서 전체를 가리키는 객체로 전역객체 window의 document 프로퍼티에 바인딩 되어 있다

2️⃣ 요소노드

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

3️⃣ 어트리뷰트 노드

  • HTML 요소의 어트리뷰트를 가리키는 객체다
  • 요소 노드는 부모노드와 연결되어 있지만, 어트리뷰트노드는 요소 노드에만 열결되어 있다

4️⃣ 텍스트 노드

  • HTML 요소의 텍스트를 가리키는 객체다
  • 자식 노드를 가질 수 없는 leaf node 이기에 DOM 트리의 최종단이다

 

 

 

노드 객체의 상속 구조

DOM을 구성하는 노드객체는 표준 빌트인 객체가 아닌 브라우저 환경에서 추가적으로 제종하는 호스트 객체이다

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

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

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

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

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

 

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

input 요소를 파싱해 객체화한 Input 요소 노드 객체는 HTMLInputElement, Element, Node, Event Target, Object 의 Prototype에 바인딩 되어있는 프로토타입 객체를 상속받는다

노드 객체의 상속구조는 개발자 도구의 Element 패널 우측 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
반응형