DOM
Document Object Model
HTML/XML 문서를 트리 구조로 표현하는 API. JavaScript로 웹 페이지를 동적으로 조작.
Document Object Model
HTML/XML 문서를 트리 구조로 표현하는 API. JavaScript로 웹 페이지를 동적으로 조작.
DOM(Document Object Model)은 HTML, XML 문서를 트리 구조의 객체 모델로 표현하는 프로그래밍 인터페이스입니다. W3C에서 표준화했으며, JavaScript가 웹 페이지의 구조, 스타일, 콘텐츠를 동적으로 읽고 수정할 수 있게 합니다. 브라우저가 HTML을 파싱하면 DOM 트리가 생성됩니다.
DOM 트리는 노드(Node)로 구성됩니다. Document(문서), Element(요소), Text(텍스트), Attribute(속성) 등의 노드 타입이 있으며, 부모-자식-형제 관계로 연결됩니다. document.getElementById(), querySelector() 같은 메서드로 노드를 탐색하고, appendChild(), removeChild()로 조작합니다.
DOM 조작은 비용이 큰 작업입니다. DOM 변경 시 브라우저는 Reflow(레이아웃 재계산)와 Repaint(화면 다시 그리기)를 수행합니다. 이 때문에 React, Vue 같은 프레임워크는 Virtual DOM을 사용해 변경 사항을 메모리에서 비교한 후 최소한의 실제 DOM 업데이트만 수행합니다.
이벤트도 DOM을 통해 처리됩니다. 클릭, 키 입력 등의 이벤트는 DOM 트리를 따라 버블링(하위→상위) 또는 캡처링(상위→하위) 방식으로 전파됩니다. 이벤트 위임(Event Delegation) 패턴을 활용하면 많은 자식 요소에 개별 리스너를 달지 않고 부모에서 효율적으로 처리할 수 있습니다.
// DOM 요소 탐색
const container = document.getElementById('app');
const buttons = document.querySelectorAll('.btn');
const firstCard = document.querySelector('.card:first-child');
// DOM 요소 생성 및 추가
const newElement = document.createElement('div');
newElement.className = 'card';
newElement.innerHTML = `
<h3>새 카드</h3>
<p>동적으로 생성된 콘텐츠</p>
`;
container.appendChild(newElement);
// 여러 요소 추가 시 DocumentFragment 사용 (성능 최적화)
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const li = document.createElement('li');
li.textContent = `아이템 ${i + 1}`;
fragment.appendChild(li);
}
document.getElementById('list').appendChild(fragment);
// → DOM 조작이 한 번만 발생 (100번 vs 1번)
// 이벤트 위임 (Event Delegation)
document.getElementById('todo-list').addEventListener('click', (e) => {
// 클릭된 요소가 삭제 버튼인지 확인
if (e.target.matches('.delete-btn')) {
const todoItem = e.target.closest('.todo-item');
todoItem.remove();
}
// 체크박스 클릭
if (e.target.matches('.todo-checkbox')) {
const todoItem = e.target.closest('.todo-item');
todoItem.classList.toggle('completed');
}
});
// 속성 및 스타일 조작
const card = document.querySelector('.card');
card.setAttribute('data-id', '123');
card.style.transform = 'translateY(-5px)';
card.classList.add('active');
card.classList.remove('hidden');
"리스트 아이템마다 이벤트 리스너를 달아놨는데 1000개 넘어가니까 메모리 사용량이 급증했어요. 부모 ul에 리스너 하나만 달고 이벤트 위임으로 처리하면 리스너가 1000개에서 1개로 줄어서 메모리 효율이 좋아집니다."
"면접관: Virtual DOM이 실제 DOM보다 빠른 이유는?
지원자: Virtual DOM 자체가 빠른 건 아니고, DOM 조작 횟수를 최소화해서 빠른 겁니다. 상태 변경 시 Virtual DOM에서 diff 알고리즘으로 변경점만 찾아 실제 DOM에 배치(batch) 업데이트합니다. 개별 DOM 조작 10번보다 배치 업데이트 1번이 reflow/repaint가 적어 성능이 좋습니다."
"for 루프 안에서 appendChild를 100번 호출하고 있네요. DocumentFragment를 사용해서 메모리에서 먼저 구성한 다음 한 번에 붙이면 reflow가 100번에서 1번으로 줄어요. 체감 성능 차이가 클 겁니다."