DOM이란 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API 즉 프로퍼티와 메서드를 제공하는 트리 자료구조입니다.
🙄HTML 요소의 구조
<div class= "greeting"> hello </div>
<div
class =
"greeting">
Hello
</div>
시작태그
어트리뷰트이름
어트리뷰트값
콘텐츠
종료태그
요소 노드로 변환
어트리뷰트 노드로변환
어트리뷰트 노드로변환
텍스트 노드로 변환
HTML 요소는 위와 같은 구조로 이루어져 있습니다.
이러한 HTML 요소는 렌더링 엔진에 의해 파싱되어서 DOM을 구성하는 요소 노드 객체로 변환됩니다.
🙄노드는 여러 종류인가요?
네
문서노드
문서 노드는 DOM트리의 최상위에 존재하는 루트노드이며 document 객체를 가리킵니다.
요소노드
요소노드는 html 요소를 가리키는 객체입니다. 요소노드는 문서의 구조를 표현합니다.
어트리뷰트 노드
어트리뷰트 노드는 HTML 요소의 어트리뷰트를 가리킵니다. 어트리뷰트 노드는 요소노드와 연결되어있습니다.
텍스트 노드
텍스트 노드는 HTML 요소의 텍스트를 가리키는 객체입니다. 텍스트노드는 요소노드의 자식입니다.
그외 노드 타입
위 4가지 외에도 다른 노드타입도 존재합니다. 총 12가지의 노드타입이 있습니다.
DOM을 구성하는 이러한 노드 객체는 ECMAScript 사양에 정의된 표준 빌트인 객체가 아니라브라우저 환경에서 추가로 제공하는 호스트 객체입니다. 하지만 노드 객체도 자바스크립트 객체이기 때문에 프로토타입에 의한 상속구조를 가집니다. 따라서 노드 객체는 상속을 통해 자신의 프로퍼티와 메서드처럼 DOM API를 사용할 수 있습니다.
🙄HTMLCollection과 Nodelist
HTMLCollection과 NodeList는 DOM API가 여러 개의 결과 값을 반환하기 위한 컬렉션 객체입니다. 이 둘은 유사 배열 객체이며 이터러블이므로 for..of 문과 스프레드 문법을 사용할 수 있습니다. 가장 중요한 특징은 live 객체라는 점으로 HTML~~는 언제나 live 객체로 동작합니다. live객체라는 것은 노드 객체의 상태 변화를 실시간으로 반영한다는 뜻 NodeList는 대부분 Non-live 객체로 동작하지만 가끔 live 객체로 동작하기도 합니다.
getElementByTagname, ClassName 메서드가 반환하는 게 HTMLCollection 객체군요 이 HTMLCollection 객체는 Live하기 때문에 for문과 같은 반복문을 사용할 때 예상과는 다르게 동작할 수 있습니다.
따라서 반복문을 굳이 사용해야한다면 i = 0이 아닌 역방향으로 반복하거나 HTMLCollection 객체를 애초에 사용하지 않는 것이 좋습니다. 예컨대 스프레드 문법으로 HTMLCollection을 배열로 바꾼 뒤 사용하는 방법을 떠올릴 수 있을 것입니다.
또는 getElements~대신 querySelectorAll 메서드를 사용하는 방법도 존재합니다. querySelectorAll은 NodeList 객체를 반환하며 이때 NodeList는 non-live 객체입니다. 그러나 childNodes 프로퍼티가 반환하는 NodeList 객체는 live 객체로 동작하므로 주의해야합니다.
live 객체이기 때문에 곤란한 문제는 Array.from 메서드 혹은 [...]문법을 통해 해결하는게 좋겠네요
🙄노드탐색 프로퍼티
요소 노드를 취득한 다음 취득 요소 노드를 기점으로 부모 형제 자식 노드를 탐색해야할 때가 있습니다. 이러한 상황에서 노드탐색 프로퍼티를 사용하게 되며 노드 탐색 프로퍼티로는 parentNode, firstChild, childNodes와 같은 프로퍼티들이 있습니다. 노드 탐색 프로퍼티는 모두 접근자 프로퍼티이며 setter가 없이 getter만 존재합니다.
🙄공백 텍스트 노드
HTML 요소 사이의 스페이스, 탭, 개행 등 공백 문자는 텍스트 노드를 생성합니다. 공백텍스트 노드는 HTMl 문서의 공백문자를 인위적으로 제거하면 생성되지 않지만 가독성이 망가지므로 사용하지 않는 편이 좋다고 합니다.
🙄innerHTML 프로퍼티의 문제점?
innerHTML 프로퍼티를 사용하면 쉽고 직관적이게 DOM을 조작할 수 있지만 크로스 사이트 스크립팅 공격에 취약하다는 단점이 있습니다.
이를 예방하기 위해 HTML 새니티제이션이라는 것이 사용됩니다. HTML 새니티제이션이란 사용자로부터 입력받은 데이터에 의해 발생할 수 있는 크로스 사이트 스크립팅 공격을 예방하기 위해 잠재적 위험을 제거하는 기능을 말합니다.
직접 함수를 구현할 수도 있지만 DOMPurify 라이브러리를 사용하는 방법도 있습니다.
//DOMPurify는 다음과같이 잠재적 위험을 내포한 HTML 마크업에서 위험을 제거합니다.
DOMPurify.sanitize('<img src="x> onerror="alert(document.cookie)">')
// => <img src="x">
또한 innerHTML은 요소 노드의 innerHTML 프로퍼티에 HTML 마크업 문자열을 할당하는 경우에 요소 노드의 모든 자식 노드를 제거하고 할당한 HTML 마크업 문자열을 파싱하여서 DOM을 변경한다는 문제점을 갖고 있습니다.
그리고 innerHTML 프로퍼티는 새로운 요소를 삽입할 때 삽입 위치를 지정할 수 없다는 문제도 갖고있습니다.
🙄HTML 어트리뷰트와 DOM 프로퍼티
HTML 어트리뷰트 HTML 요소의 초기 상태를 지정하며 HTML 어트리뷰트의 값은 HTML 요소의 초기 상태를 의미하고 이는 변하지 않습니다.
DOM 프로퍼티 사용자가 입력한 최신 상태는 HTML 어트리뷰트에 대응하는 요소 노드의 DOM 프로퍼티가 관리합니다. DOM 프로퍼티는 사용자의 입력에 의한 상태 변화에 반응하며 언제나 최신 상태를 유지합니다.
🙄이벤트 드리븐 프로그래밍?
이벤트 드리븐 프로그래밍이란 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식을 말합니다.
🙄이벤트 핸들러 등록
이벤트 핸들러를 등록하는 방법으로는 이벤트 핸들러 어트리뷰트 방식, 이벤트 핸들러 프로퍼티 방식, addEventListener 방식이 있습니다.
위 예제에서 이벤트리스너 메서드 방식은 이벤트 핸들러 프로퍼티에 바인딩된 이벤트 핸들러에 아무 영향을 주지 않습니다. 따라서 버튼에 클릭 이벤트가 발생하면 2개의 이벤트 핸들러가 모두 호출됩니다.
이렇듯 이벤트 핸들러 프로퍼티 방식은 하나 이상의 이벤트핸들러를 등록할 수 없지만 이벤트리스너를 사용하면 하나 이상을 할당할 수도 있으면서 이벤트 핸들러는 등록된 순서대로 호출됩니다.
🙄이벤트 객체
이벤트가 발생하면 이벤트에 관련한 정보를 담고 있는 이벤트 객체가 동적으로 생성되며 이 이벤트 객체는 이벤트 핸들러의 첫번째 인수로 전달됩니다. 이벤트 객체의 프로퍼티는 발생한 이벤트의 타입에 따라 달라집니다. 하지만 공통적으로 상속받는 공통 프로퍼티도 존재합니다. 예컨대 type,target,currentTarget,bubbles 등이 있습니다.
🙄이벤트 전파
DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파되며 이를 이벤트 전파라고 합니다.
이벤트 전파는 방향에 따라 3단계로 구분합니다. 캡쳐링 단계 : 이벤트가 상위 요소 -> 하위요소 방향으로 전파되는 것 타깃 단계 : 이벤트가 이벤트 타깃에 도달하는 것 버블링 단계 : 이벤트가 하위 요소에서 상위 요소 방향으로 전파되는 것
캡쳐링 -> 타깃 -> 버블링 순으로 이벤트는 전파되게 됩니다.
이때문에 이벤트는 이벤트를 발생시킨 이벤트 타깃은 물론 상위 DOM 요소에서도 캐치할 수 있습니다. DOM 트리를 통해 전파되는 이벤트는 이벤트가 통과하는 경로에 위치한 모든 DOM 요소에서 캐치할 수 있는거죠!!
버블링은 event.stopPropagation()을 이용해서 인위적으로 막을 수 있지만 권장되지는 않는다고 합니다.
🙄이벤트 위임
이벤트 위임이란 여러개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법을 말합니다. 이벤트 위임은 앞서 본 캡처링과 버블링을 활용합니다.
이벤트는 이벤트 타깃은 물론이고 상위 DOM 요소에서도 캐치할 수 있기 때문에 이벤트 위임을 통해 상위 DOM 요소에 이벤트 핸들러를 등록해두면 여러 하위 DOM 요소에 동일한 이벤트 핸들러를 일일히 등록할 필요가 없는거죠!
🙄이벤트 핸들러 내부의 this
이벤트 핸들러 어트리뷰트 방식의 경우 this 는 전역객체 window를 가리킵니다. 반면 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드는 모두 이벤트 핸들러 내부의 this가 이벤트를 바인딩한 DOM 요소를 가리킵니다.
따라서 이벤트 핸들러 내부의 this는 이벤트 객체의 currentTarget 프로퍼티와 같습니다.