인사이트
문서 객체 모델 DOM 과 자바스크립트 JavaScriptㅣ생성 방식 및 접근 방법
2022년 09월 16일
프론트엔드 개발자라면 자바스크립트(JavaScript)라는 프로그래밍 언어를 아는 것과 동시에, DOM에 대해서 반드시 알고 있어야만 웹 개발을 시작할 수 있다고 해도 과언이 아닙니다. 브라우저에 띄울 웹 페이지가 단순히 정보 전달만을 목적으로 하는 정적인 웹이라면 HTML, CSS로도 충분하겠지만 그 이상의 인터랙티브한 기능을 구현하고자 한다면 자바스크립트와 DOM을 반드시 써야만 하기 때문입니다.
그렇다면 DOM이란 무엇이고, 어떻게 자바스크립트와 DOM을 이용해 인터랙티브한 기능을 구현할 수 있는지 알아보도록 하겠습니다.
먼저 DOM, 문서 객체 모델이 무엇인지에 대해 살펴볼게요.
문서 객체 모델, 즉 DOM은 웹 페이지(HTML이나 XML 문서)의 콘텐츠 및 구조, 그리고 스타일 요소를 구조화 시켜 표현하여 프로그래밍 언어가 해당 문서에 접근하여 읽고 조작할 수 있도록 API를 제공하는 일종의 인터페이스입니다. 즉 자바스크립트 같은 스크립팅 언어가 쉽게 웹 페이지에 접근하여 조작할 수 있게끔 연결시켜주는 역할을 담당합니다.
DOM은 웹 페이지, 즉 HTML 문서를 계층적 구조와 정보로 표현하며, 이를 제어할 수 있는 프로퍼티와 메서드를 제공하는 트리 자료구조이기도 합니다. 따라서 HTML DOM, 혹은 HTML DOM Tree로 부르기도 합니다.
트리 자료구조는 노드들의 계층 구조로 이루어져 있습니다. 계층 구조로 이루어져 있기 때문에 부모-자식 관계, 형제관계를 표현하는 비선형 자료구조를 나타냅니다.
트리 자료 구조로 구축이 되기 때문에, HTML 문서는 최종적으로 하나의 최상위 노드(root 노드)에서 시작해 자식 노드들을 가지며, 아래로만 뻗어나가는 구조로 만들어지게 됩니다.
어떻게 DOM으로 표현될 수 있는지 간단한 구조로 되어 있는 웹페이지를 보도록 하겠습니다.
이 웹페이지를 코드로 표현해보겠습니다.
이렇게 HTML 문서 안에 h2 태그로 감싸진 text가 존재하고 있을 것입니다. 해당 문서는 트리 구조로 표현한다면 이렇게 표현이 될 수 있어요.
document 노드가 최상위 노드가 되고, 밑으로 element 노드가 오며, 이어 text 노드와 attribute 노드가 오는 계층적인 구조임을 알 수 있습니다. 이러한 노드 타입에는 총 12개가 있는데 가장 중요한 것은 위에서도 명시가 되어 있듯 총 4가지의 노드가 있습니다.
DOM Tree에서 최상위 루트 노드를 나타내며, document 객체를 가리킵니다. HTML 문서 전체를 나타내는 노드이기도 합니다. window 객체의 document 프로퍼티로 바인딩(연결)이 되어 있어 window.document , document로 참조해 사용할 수 있습니다. HTML 문서에 이 문서 노드는 오로지 1개만 존재합니다.
모든 HTML 요소 (body, h2, div 등)는 이 요소 노드입니다. 속성 노드를 가질 수 있는 유일한 노드로서, 부모-자식 관계를 가지게 되기 때문에 계층적 구조를 이룰 수 있게 됩니다.
모든 HTML 요소의 속성은 이 속성 노드입니다. 요소 노드에 대한 정보를 가지고 있습니다. 그렇기 때문에 부모 노드가 아닌 해당 노드와 연결(바인딩)이 되어 있습니다.
HTML 문서의 모든 텍스트는 이 텍스트 노드라 해도 과언이 아닙니다. 텍스트 노드는 정보를 표현하며, 가장 마지막에 위치하는 자식 노드이기 때문에 잎사귀를 닮았다 해 리프 노드라고 불리기도 합니다.
이 4가지 노드들이 존재함으로써 스크립팅 언어가 웹페이지에 접근하고 조작할 수 있게 됩니다. 특히 데이터 검색하기가 빠른 트리 구조로 이뤄져 있기 때문에 이 접근하고 조작하여 업데이트를 하는 속도는 빠른 편입니다.
자바스크립트와 DOM은 어떤 관계일까요?
자바스크립트는 DOM을 조작할 수 있는 프로그래밍 언어 중에서 가장 유명한 언어입니다. 웹페이지를 만듦에 있어서 거의 한 몸처럼 사용하게 되다 보니, 가끔 자바스크립트와 DOM을 혼동해 “자바스크립트 안에 DOM이 있는 거 아니냐” 혹은 “DOM은 자바스크립트로만 다룰 수 있는 거 아니냐” 같은 심심한 오해가 생기게 되기도 합니다.
그러나 자바스크립트와 DOM은 엄밀히 다른 개념이며, 꼭 자바스크립트로만 DOM을 다룰 수 있는 것도 아닙니다.
DOM은 자바스크립트 없이 DOM 인터페이스 구현만으로도 DOM을 조작할 수 있기 때문입니다. DOM은 앞서 프로그래밍 언어가 해당 문서에 접근하여 읽고 조작할 수 있도록 API를 제공하는 일종의 인터페이스라고 설명했습니다. 조금 더 부연 설명을 하자면 DOM은 어떤 프로그래밍 언어에 의존하지 않는 독립적인 인터페이스라는 것입니다.
이렇기 때문에 DOM은 꼭 자바스크립트로만 구현 되는 것도 아닙니다. 다른 프로그래밍 언어인 자바로도 구현할 수 있으며, C#으로도 구현할 수 있습니다. 그렇다면 왜 이런 오해가 생겼을까요?
현재 웹 브라우저에서 DOM을 조작하는 언어는 자바스크립트 뿐이기 때문입니다. 브라우저는 과거 HTML 문서로만 이루어진 웹 페이지를 출력하기만 했고, 그것만으로도 충분했었습니다. 그러나 점점 시간이 흐르며 동적인 기능을 요구하기 시작했고, HTML 문서 만으로는 이 기능을 제공하기 불가능 해졌습니다.
그래서 웹 브라우저 내부에 이 동적인 기능을 지원해줄 프로그래밍 언어를 넣기로 했는데, 현재의 자바스크립트의 초석이 되는 Mocha(모카)입니다. 웹 브라우저는 이 때 이후 내장 프로그래밍 언어로 쭉 자바스크립트를 고수해오고 있습니다. 그렇기 때문에 다른 언어로도 DOM을 조작할 수 있는 것은 분명하나, 브라우저를 꽉 잡고 있는 자바스크립트의 아성을 이기지는 못하는 것도 사실입니다.
어찌 되었든 결론적으로, 만일 브라우저가 자바스크립트 외에 다른 언어를 지원하게 된다 하더라도 DOM은 프로그래밍 언어와 독립적으로 구현됩니다. 따라서 자바스크립트가 아니더라도 그 언어를 통해 DOM을 사용하여 동일한 방식으로 HTML 문서를 조작하고 화면을 렌더링할 수 있을 것입니다.
지금 현재 브라우저에 내장되어 있는 언어는 자바스크립트이고, 자바스크립트는 가장 간편하고 빠르게 DOM으로 구조화된 웹 문서에 접근하여 노드(웹 컨텐츠를 이루는 기본 요소)들을 조작할 수 있습니다.
엄밀히 말하자면, 자바스크립트를 이용해 HTML 문서에 없는 노드를 만들어 이어 붙여 웹 페이지에 렌더링되게 만드는 모든 과정이 동적으로 구현하는 것이라 볼 수 있습니다. 또는 자바스크립트를 이용해 있던 노드에 없는 노드를 만들어 이어 붙이는 것도 동적으로 구현한다고 볼 수 있죠.
정적으로 생성되는 과정은 오로지 이미 HTML 파일에 적혀 있는 코드를 위에서부터 아래로 읽어내려가며 생성하는 과정만을 뜻합니다. 즉 HTML 문서에 직접 태그로 작성하는 것만을 정적으로 생성한다고 보기 때문에, 이런 부분에서 차이가 날 수밖에 없습니다.
즉, 이 코드를 읽어내려 웹페이지에 콘텐츠를 띄우는 과정은 정적 생성 과정입니다. 여기에는 자바스크립트가 접근하여 DOM을 조작한 흔적이 없습니다.
그러나 밑에 스크립트 태그를 달아 외부의 자바스크립트 파일을 연결하고, h2 태그에 id를 달아 일련의 작업(예를 들어 h2 태그를 클릭하면 밑에 사진이 나타나는 등의 동작)을 하게 된다면 이것은 동적으로 노드를 생성한다고 보는 것입니다.
먼저 DOM 객체의 구성 요소부터 알아보도록 하겠습니다.
이제부터 DOM의 중요한 데이터 타입들에 대해 알아보도록 하겠습니다. 데이터 타입에는 여러 개가 있는데, 데이터 타입은 객체이기 때문에 각각 프로퍼티와 메소드를 가지고 있습니다.
member(프로퍼티 혹은 메서드)가 document 타입의 object를 리턴할 때, 이 object는 root document object 자체입니다. 예를 들어 element의 ownerDocument property(ex. document.getElementById("myP").ownerDocument)는 해당 프로퍼티가 속해 있는 document를 return 합니다.
documentobject 에 대한 설명은 DOM document Reference에서 더 자세히 볼 수 있습니다.
element는 DOM API 의 member에 의해 return 된 element 또는 element 타입의 노드를 의미합니다.
document.createElement() method 가 node를 참조하는 object 를 리턴한다고 말하는 대신, 이 method가 DOM 안에서 생생되는 element를 리턴한다고 좀 더 단순하게 말할 수 있습니다. element 객체들은 DOM Element 인터페이스와 함께, 좀 더 기본적인 Node 인터페이스를 구현한 것이기 때문에 이 참조(reference)에는 두 가지가 모두 포함되었다고 생각하면 됩니다.
element object에 대한 설명은 DOM element Reference에서 더 자세히 볼 수 있습니다.
nodeList 는 element의 배열입니다. (document.getElementsByTagName() method에 의해 리턴된 것과 같습니다.) nodeList의 Items 은 index 를 통해 접근 가능하며, 다음과 같이 두 가지 방식이 있습니다.
1. list.item(1)
2. list[1]
위의 방식들은 동일합니다. 1번의 item() method는 nodeList object의 단일 method입니다. 2번은 list에서 두번째 item을 가져오는(fetch) 전형적인 array 문법(syntax)입니다.
nodeList object에 대한 설명은 DOM nodeList Reference에서 더 자세히 볼 수 있습니다.
namedNodeMap는 배열과 유사하지만 안의 요소에 접근할 때 name 또는 index로 접근합니다. 리스트는 특별한 정렬이 적용되지 않았기 때문에 열거(enumeration) 할 때 index를 주로 사용합니다. namedNodeMap는 이를 위해 item() method 가 있으며, namedNodeMap에 item 을 추가하거나 삭제할 수 있다.
namedNodeMap object에 대한 설명은 DOM namedNodeMap Reference에서 더 자세히 볼 수 있습니다.
자바스크립트로 DOM에 접근하는 방법은, DOM의 인터페이스를 이용하여 접근할 수 있습니다. 기본적으로 브라우저 내부에 내장된 프로그래밍 언어(즉 자바스크립트)가 DOM의 API 중 자주 쓰는 메소드와 프로퍼티가 있는데,
등이 있습니다. 대개 위에 있는 것들을 많이 이용해 동적으로 노드를 생성하거나 삭제, 혹은 변경이 가능합니다. 위에 있는 메소드를 이용하여 자바스크립트가 DOM에 접근하여 동적으로 노드를 생성하고, 수정 및 삭제하는 것을 보도록 하겠습니다.
div
라는 변수에 document.createElement()
를 이용하여 이용하여 div 노드를 만들어 담아둔(할당한) 상태입니다. 이 상태에서 div
라는 변수를 불러오면(호출) div 태그가 뜨는 것이 확인이 됩니다. 여기서 이 div 태그의 특징은 화면에는 적용이 되지 않는다는 점입니다. 실제로 적용을 시키려면 append()
, 혹은 appendChild()
메소드를 사용하여 화면에 붙여야만 합니다.
div 태그를 붙이기 위해 먼저 이행해야 할 일은, 부모 노드에 접근하는 것입니다. 여기서 부모 노드는, 다른 태그가 존재하지 않는 한 body 태그가 부모 태그입니다.
이것이 HTML 초기 파일입니다. 보시다시피 body 태그 안에는 아무것도 입력이 되어 있지 않습니다. 따라서 이 상태에서 div 태그를 넣기 위해서는 부모 노드를 body로 설정하고 접근한 상태에서 append()
, 혹은 appendChild()
메소드를 사용해야 합니다.
노드 내부에 어떤 변경이 일어나면 DOM은 업데이트를 진행하고 다시 화면을 출력(렌더링)합니다. 이 과정을 가장 간단하게 보여줄 수 있는 방법은 요소 노드 내부에 textContent 프로퍼티를 사용하여 text를 집어넣는 방법입니다.
변수 div
뒤에 textContent
프로퍼티를 붙이고, 넣고자 하는 텍스트를 입력하면 화면에 바로 반영이 됩니다. 이 코드는 최종적으로 이런 모양이 될 것입니다.
script 태그를 파일로 따로 분리하지 않고 안에서 자바스크립트를 이용하여 DOM에 접근해 노드를 생성하고, 붙인 뒤 노드를 업데이트하고 있습니다. body 태그 내부에는 정적으로 입력된 태그가 하나도 존재하지 않습니다. 그러나 브라우저는 script 태그 내의 코드를 차례대로 읽어 내려가 해석하며 노드를 동적으로 생성하여 업데이트하게 됩니다. 이 동적 생성을 잘 이용하면 인터랙티브한 기능을 구현할 수 있게 됩니다.
노드를 삭제하는 방법에도 두 가지가 존재하고 있습니다. remove()
와 removeChild()
메소드는 노드를 이어붙이는 메소드(append()
, appendChild()
)와는 달리 둘 다 부모 태그에 접근하지 않는다는 점입니다. removeChild()
메소드는 부모 태그에 접근해야만 자식 태그를 제거할 수 있습니다. 그러나 이와 달리 remove()
메소드는 자식 태그에 접근해서 제거하는 메소드입니다. 만일 이 메소드로 부모 태그에 접근하게 된다면 부모 태그까지 지워지게 됩니다.
이렇게 자바스크립트로 DOM을 조작하는 간단한 예시를 보았습니다. 이번에는 버튼을 클릭하면 고양이 사진이 나오는 간단한 예시를 코드를 통해 보도록 하겠습니다.
<button id="cat">cat</button>
<script>
document.querySelector("#cat").onclick = function() {
let img = document.createElement("img");
img.setAttribute("src", "넣고자 하는 그림 주소 or 파일");
img.setAttribute("style", "width:300px;margin-top:20px;")
document.body.append(img);
};
</script>
button 태그를 정적으로 생성한 뒤, script 태그 내에서 동적으로 버튼을 찾고 버튼에 onclick 이벤트 리스너를 붙여 고양이 이미지를 생성하고 있습니다.
조금 더 자세히 설명해 보자면 script 태그 내에서 button 태그에 부여한 id를 기준으로 버튼을 찾아옵니다. 찾아온 버튼에 onclick 이벤트 리스너를 붙여 함수 안에 이미지 태그를 생성하고, setAttribute() 메소드를 사용해 이미지의 src와 style을 부여하여 부모 태그인 body에 붙이고 있습니다. 예상대로 동작하는 지 확인해 볼까요?
예상했던 대로 버튼을 누르는 동시에 body 태그에 img 태그가 붙고 있음을 확인할 수 있습니다.
이 외에도 다양한 예시들이 있습니다. 이런 예시들을 모아놓은 가장 대표적인 사이트로는 w3 schools가 있습니다. 해당 사이트에 접속하면 HTML DOM에 관련된 다양한 예시들을 확인할 수 있습니다. 해당 예시들을 확인해보세요!
이렇게 DOM은 무엇이고, 자바스크립트와 DOM은 어떤 관계이며 자바스크립트로 DOM에 접근해 동적으로 Element를 생성하는 것에 대해서 알아보았습니다. 재미있게 읽으셨나요? 모든 웹 개발의 시작은 자바스크립트와 DOM에서 시작한다고 해도 과하지 않습니다. 웹 개발에 대해 조금만 관심이 있으시다면, react라던가 vue 같은 것들도 접하실 수 있을 텐데, 이 또한 뿌리는 자바스크립트와 DOM이기 때문입니다.
위에서 다룬 자바스크립트, DOM을 포함하여 개발 분야에 흥미가 있고 프론트엔드 관련 분야의 커리어를 꿈꾸고 계신가요? 코드스테이츠 프론트엔드 개발 부트캠프 과정은 JavaScript 언어를 기반으로 수강생을 사용자 친화적인 웹 서비스를 만드는 개발자로 성장시키기 위한 체계적인 커리큘럼을 제공하고 있습니다. 페어 프로그래밍과 팀 프로젝트 협업을 통해 커뮤니케이션 역량을 쌓고, 메타인지 학습모델을 적용한 학습 콘텐츠 및 알고리즘 문제를 푸는 데일리 코딩 시간을 통해 문제해결 능력을 키울 수 있죠.
예비 개발자를 위한 전문 커리어 코칭까지 준비되어 있는 코드스테이츠 프론트엔드 개발 부트캠프가 더 궁금하다면 아래 버튼을 통해 더 자세한 내용을 살펴보세요!
글 정해림 Educational Software Engineer (프론트엔드 개발 부트캠프)
편집 조주연 Content Manager
👩💻 개발자 커리어의 시작,
코드스테이츠 부트캠프가 더 궁금하다면?
목록 보기
추천글