2026년 8월 5일

뮤테이션 옵저버

MutationObserver는 DOM 요소를 관찰하다가 변경이 감지되면 콜백을 실행하는 내장 객체입니다.

먼저 문법을 알아본 다음 실제 사례를 보면서 뮤테이션 옵저버가 어디에 유용한지 살펴보겠습니다.

문법

MutationObserver 사용법은 간단합니다.

먼저 콜백 함수를 넘겨 옵저버를 만듭니다.

let observer = new MutationObserver(callback);

그리고 만든 옵저버를 DOM 노드에 붙입니다.

observer.observe(node, config);

config는 '어떤 종류의 변경에 반응할지’를 나타내는 불린값 옵션이 담긴 객체입니다.

  • childListnode의 직계 자식에서 일어나는 변경
  • subtreenode의 모든 자손에서 일어나는 변경
  • attributesnode의 속성 변경
  • attributeFilter – 선택한 속성만 관찰하도록 속성 이름을 담은 배열
  • characterDatanode.data(텍스트 콘텐츠)를 관찰할지 여부

이 외에 다음 옵션도 있습니다.

  • attributeOldValuetrue이면 속성의 이전 값과 새 값을 모두 콜백에 전달하고(아래 참고) 그렇지 않으면 새 값만 전달함(attributes 옵션 필요)
  • characterDataOldValuetrue이면 node.data의 이전 값과 새 값을 모두 콜백에 전달하고(아래 참고) 그렇지 않으면 새 값만 전달함(characterData 옵션 필요)

옵저버를 붙인 DOM 노드에 실제 변경이 생길 때마다 callback이 실행됩니다. 이때 콜백 함수의 첫 번째 인수로 MutationRecord 객체 목록이, 두 번째 인수로 옵저버 자신이 전달됩니다.

MutationRecord 객체에는 다음과 같은 프로퍼티가 있습니다.

  • type – 뮤테이션 타입으로 다음 중 하나
    • "attributes": 속성이 수정됨
    • "characterData": 데이터가 수정됨. 텍스트 노드에 사용됨
    • "childList": 자식 요소가 추가되거나 삭제됨
  • target – 변경이 일어난 곳. "attributes" 뮤테이션이면 요소, "characterData" 뮤테이션이면 텍스트 노드, "childList" 뮤테이션이면 요소
  • addedNodes/removedNodes – 추가되거나 삭제된 노드
  • previousSibling/nextSibling – 추가되거나 삭제된 노드의 이전·다음 형제 노드
  • attributeName/attributeNamespace – 변경된 속성의 이름과 (XML의) 네임스페이스
  • oldValue – 이전 값. 속성이나 텍스트가 변경되었고 해당 옵션 attributeOldValue/characterDataOldValue가 설정된 경우에만 전달됨

예시를 살펴봅시다. 아래 <div>에는 contentEditable 속성이 있어서 포커스를 준 뒤 내용을 수정할 수 있습니다.

<div contentEditable id="elem">여기를 클릭해 <b>수정</b>해 보세요</div>

<script>
let observer = new MutationObserver(mutationRecords => {
  console.log(mutationRecords); // 변경 사항이 출력됩니다.
});

// 속성을 제외한 모든 변경을 관찰합니다.
observer.observe(elem, {
  childList: true, // 직계 자식을 관찰함
  subtree: true, // 하위 자손도 관찰함
  characterDataOldValue: true // 이전 데이터도 콜백에 전달함
});
</script>

우측 상단 재생 버튼을 눌러 코드를 브라우저에서 실행하고 <div>에 포커스를 준 다음 <b>수정</b> 안의 텍스트를 바꾸면 console.log 때문에 개발자 도구에 뮤테이션 하나가 출력됩니다.

mutationRecords = [{
  type: "characterData",
  oldValue: "수정",
  target: <text node>,
  // 다른 프로퍼티는 비어 있음
}];

<b>수정</b>을 통째로 지우는 등 더 복잡한 방식으로 수정을 하면 뮤테이션 이벤트에 뮤테이션 레코드가 여러 개 담길 수 있습니다.

mutationRecords = [{
  type: "childList",
  target: <div#elem>,
  removedNodes: [<b>],
  nextSibling: <text node>,
  previousSibling: <text node>,
  // 다른 프로퍼티는 비어 있음
}, {
  type: "characterData",
  target: <text node>,
  // ...뮤테이션의 세부 내용은 브라우저가 이런 삭제를 어떻게 처리하는지에 따라 다릅니다.
  // 인접한 두 텍스트 노드 '여기를 클릭해 '와 '해 보세요'를 하나로 합칠 수도 있고
  // 별개의 텍스트 노드로 남겨둘 수도 있습니다.
}];

이처럼 MutationObserver를 사용하면 DOM 서브트리에서 일어나는 모든 변경에 반응할 수 있습니다.

서드파티 스크립트 통합에 활용하기

뮤테이션 옵저버는 어떤 경우에 유용할까요?