From 911f85bcaddd3ed82cc08f3b2b39dc779bc92fc3 Mon Sep 17 00:00:00 2001 From: Bora Lee Date: Sun, 19 Jul 2026 01:44:32 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Part=202.=205.1=20Mutation=20observer=20?= =?UTF-8?q?=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Ezn3Dq7aWbVPvWonrUn8YK --- .../01-mutation-observer/article.md | 208 +++++++++--------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/2-ui/99-ui-misc/01-mutation-observer/article.md b/2-ui/99-ui-misc/01-mutation-observer/article.md index 3cf6f53977..96d7d77047 100644 --- a/2-ui/99-ui-misc/01-mutation-observer/article.md +++ b/2-ui/99-ui-misc/01-mutation-observer/article.md @@ -1,82 +1,82 @@ -# Mutation observer +# 뮤테이션 옵저버 -`MutationObserver` is a built-in object that observes a DOM element and fires a callback when it detects a change. +`MutationObserver`는 DOM 요소를 관찰하다가 변경이 감지되면 콜백을 실행하는 내장 객체입니다. -We'll first take a look at the syntax, and then explore a real-world use case, to see where such thing may be useful. +먼저 문법을 알아본 다음 실제 사례를 보면서 뮤테이션 옵저버가 어디에 유용한지 살펴보겠습니다. -## Syntax +## 문법 -`MutationObserver` is easy to use. +`MutationObserver`는 사용법이 간단합니다. -First, we create an observer with a callback-function: +먼저 콜백 함수를 넘겨 옵저버를 만듭니다. ```js let observer = new MutationObserver(callback); ``` -And then attach it to a DOM node: +그리고 만든 옵저버를 DOM 노드에 붙입니다. ```js observer.observe(node, config); ``` -`config` is an object with boolean options "what kind of changes to react on": -- `childList` -- changes in the direct children of `node`, -- `subtree` -- in all descendants of `node`, -- `attributes` -- attributes of `node`, -- `attributeFilter` -- an array of attribute names, to observe only selected ones. -- `characterData` -- whether to observe `node.data` (text content), +`config`는 '어떤 종류의 변경에 반응할지'를 나타내는 불린값 옵션이 담긴 객체입니다. +- `childList` -- `node`의 직계 자식에서 일어나는 변경 +- `subtree` -- `node`의 모든 자손에서 일어나는 변경 +- `attributes` -- `node`의 속성 변경 +- `attributeFilter` -- 선택한 속성만 관찰하도록 속성 이름을 담은 배열 +- `characterData` -- `node.data`(텍스트 콘텐츠)를 관찰할지 여부 -Few other options: -- `attributeOldValue` -- if `true`, pass both the old and the new value of attribute to callback (see below), otherwise only the new one (needs `attributes` option), -- `characterDataOldValue` -- if `true`, pass both the old and the new value of `node.data` to callback (see below), otherwise only the new one (needs `characterData` option). +이 외에 다음 옵션도 있습니다. +- `attributeOldValue` -- `true`이면 속성의 이전 값과 새 값을 모두 콜백에 전달하고(아래 참고) 그렇지 않으면 새 값만 전달함(`attributes` 옵션 필요) +- `characterDataOldValue` -- `true`이면 `node.data`의 이전 값과 새 값을 모두 콜백에 전달하고(아래 참고) 그렇지 않으면 새 값만 전달함(`characterData` 옵션 필요) -Then after any changes, the `callback` is executed: changes are passed in the first argument as a list of [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) objects, and the observer itself as the second argument. +이후 변경이 생길 때마다 `callback`이 실행됩니다. 이때 첫 번째 인수로 [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) 객체 목록이, 두 번째 인수로 옵저버 자신이 전달됩니다. -[MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) objects have properties: +[MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) 객체에는 다음과 같은 프로퍼티가 있습니다. -- `type` -- mutation type, one of - - `"attributes"`: attribute modified - - `"characterData"`: data modified, used for text nodes, - - `"childList"`: child elements added/removed, -- `target` -- where the change occurred: an element for `"attributes"`, or text node for `"characterData"`, or an element for a `"childList"` mutation, -- `addedNodes/removedNodes` -- nodes that were added/removed, -- `previousSibling/nextSibling` -- the previous and next sibling to added/removed nodes, -- `attributeName/attributeNamespace` -- the name/namespace (for XML) of the changed attribute, -- `oldValue` -- the previous value, only for attribute or text changes, if the corresponding option is set `attributeOldValue`/`characterDataOldValue`. +- `type` -- 뮤테이션 타입으로 다음 중 하나 + - `"attributes"`: 속성이 수정됨 + - `"characterData"`: 데이터가 수정됨. 텍스트 노드에 사용됨 + - `"childList"`: 자식 요소가 추가되거나 삭제됨 +- `target` -- 변경이 일어난 곳. `"attributes"` 뮤테이션이면 요소, `"characterData"` 뮤테이션이면 텍스트 노드, `"childList"` 뮤테이션이면 요소 +- `addedNodes/removedNodes` -- 추가되거나 삭제된 노드 +- `previousSibling/nextSibling` -- 추가되거나 삭제된 노드의 이전·다음 형제 노드 +- `attributeName/attributeNamespace` -- 변경된 속성의 이름과 (XML의) 네임스페이스 +- `oldValue` -- 이전 값. 속성이나 텍스트가 변경되었고 해당 옵션 `attributeOldValue`/`characterDataOldValue`가 설정된 경우에만 전달됨 -For example, here's a `
` with a `contentEditable` attribute. That attribute allows us to focus on it and edit. +예시를 살펴봅시다. 아래 `
`에는 `contentEditable` 속성이 있어서 포커스를 준 뒤 내용을 수정할 수 있습니다. ```html run -
Click and edit, please
+
여기를 클릭해 수정해 보세요
``` -If we run this code in the browser, then focus on the given `
` and change the text inside `edit`, `console.log` will show one mutation: +위 코드를 브라우저에서 실행하고 `
`에 포커스를 준 다음 `수정` 안의 텍스트를 바꾸면 `console.log`에 뮤테이션 하나가 출력됩니다. ```js mutationRecords = [{ type: "characterData", - oldValue: "edit", + oldValue: "수정", target: , - // other properties empty + // 다른 프로퍼티는 비어 있음 }]; ``` -If we make more complex editing operations, e.g. remove the `edit`, the mutation event may contain multiple mutation records: +`수정`을 통째로 지우는 등 더 복잡하게 수정하면 뮤테이션 이벤트에 뮤테이션 레코드가 여러 개 담길 수 있습니다. ```js mutationRecords = [{ @@ -85,75 +85,75 @@ mutationRecords = [{ removedNodes: [], nextSibling: , previousSibling: - // other properties empty + // 다른 프로퍼티는 비어 있음 }, { type: "characterData" target: - // ...mutation details depend on how the browser handles such removal - // it may coalesce two adjacent text nodes "edit " and ", please" into one node - // or it may leave them separate text nodes + // ...뮤테이션의 세부 내용은 브라우저가 이런 삭제를 어떻게 처리하는지에 따라 다릅니다. + // 인접한 두 텍스트 노드 '여기를 클릭해 '와 '해 보세요'를 하나로 합칠 수도 있고 + // 별개의 텍스트 노드로 남겨둘 수도 있습니다. }]; ``` -So, `MutationObserver` allows to react on any changes within DOM subtree. +이처럼 `MutationObserver`를 사용하면 DOM 서브트리에서 일어나는 모든 변경에 반응할 수 있습니다. -## Usage for integration +## 서드파티 스크립트 통합에 활용하기 -When such thing may be useful? +뮤테이션 옵저버는 어떤 경우에 유용할까요? -Imagine the situation when you need to add a third-party script that contains useful functionality, but also does something unwanted, e.g. shows ads `
Unwanted ads
`. +유용한 기능이 들어 있지만 원치 않는 동작도 하는 서드파티 스크립트를 추가해야 하는 상황을 상상해 봅시다. 이 스크립트는 `
원치 않는 광고
`같이 광고를 노출합니다. -Naturally, the third-party script provides no mechanisms to remove it. +당연하게도 서드파티 스크립트엔 광고를 제거할 수단이 없습니다. -Using `MutationObserver`, we can detect when the unwanted element appears in our DOM and remove it. +`MutationObserver`를 사용하면 원치 않는 요소가 DOM에 나타나는 순간을 감지해 제거할 수 있습니다. -There are other situations when a third-party script adds something into our document, and we'd like to detect, when it happens, to adapt our page, dynamically resize something etc. +이 외에도 서드파티 스크립트가 문서에 무언가를 추가하는 시점을 감지해서 페이지를 조정하거나 특정 영역의 크기를 동적으로 조절하고 싶은 경우도 있습니다. -`MutationObserver` allows to implement this. +이런 작업 역시 `MutationObserver`로 구현할 수 있습니다. -## Usage for architecture +## 아키텍처 관점에서 활용하기 -There are also situations when `MutationObserver` is good from architectural standpoint. +아키텍처 관점에서 `MutationObserver`가 좋은 선택이 되는 경우도 있습니다. -Let's say we're making a website about programming. Naturally, articles and other materials may contain source code snippets. +프로그래밍을 다루는 웹사이트를 만들고 있다고 가정해 봅시다. 이런 사이트의 글이나 자료엔 소스 코드 예시가 들어가기 마련입니다. -Such snippet in an HTML markup looks like this: +코드 예시는 HTML 마크업에서 다음과 같은 모습입니다. ```html ...

-  // here's the code
+  // 여기에 코드가 들어갑니다.
   let hello = "world";
 
... ``` -For better readability and at the same time, to beautify it, we'll be using a JavaScript syntax highlighting library on our site, like [Prism.js](https://prismjs.com/). To get syntax highlighting for above snippet in Prism, `Prism.highlightElem(pre)` is called, which examines the contents of such `pre` elements and adds special tags and styles for colored syntax highlighting into those elements, similar to what you see in examples here, on this page. +가독성을 높이는 동시에 보기 좋게 꾸미기 위해 [Prism.js](https://prismjs.com/) 같은 자바스크립트 구문 강조(syntax highlighting) 라이브러리를 사이트에 사용해 보겠습니다. Prism에서 위 예시에 구문 강조를 적용하려면 `Prism.highlightElem(pre)`를 호출합니다. 이 메서드는 `pre` 요소의 내용을 검사해서 색을 입히는 특별한 태그와 스타일을 해당 요소 안에 추가합니다. 지금 보고 있는 이 페이지의 예시와 비슷한 결과물이 만들어지죠. -When exactly should we run that highlighting method? Well, we can do it on `DOMContentLoaded` event, or put the script at the bottom of the page. The moment our DOM is ready, we can search for elements `pre[class*="language"]` and call `Prism.highlightElem` on them: +그렇다면 구문 강조 메서드는 정확히 언제 실행해야 할까요? `DOMContentLoaded` 이벤트에서 실행할 수도 있고 스크립트를 페이지 맨 아래에 넣을 수도 있습니다. DOM이 준비되면 `pre[class*="language"]`에 해당하는 요소를 찾아 `Prism.highlightElem`을 호출하면 됩니다. ```js -// highlight all code snippets on the page +// 페이지에 있는 코드 예시를 전부 강조 표시합니다. document.querySelectorAll('pre[class*="language"]').forEach(Prism.highlightElem); ``` -Everything's simple so far, right? We find code snippets in HTML and highlight them. +여기까진 문제 될 게 없습니다. HTML에서 코드 예시를 찾아 강조 표시하면 끝이죠. -Now let's go on. Let's say we're going to dynamically fetch materials from a server. We'll study methods for that [later in the tutorial](info:fetch). For now it only matters that we fetch an HTML article from a webserver and display it on demand: +이제 한 걸음 더 나아가 봅시다. 서버에서 자료를 동적으로 가져와야 한다고 해봅시다. 자료를 가져오는 메서드는 [튜토리얼 뒷부분](info:fetch)에서 다룰 예정이라 지금은 웹 서버에서 HTML로 된 글을 받아와 요청이 있을 때 화면에 표시한다는 점만 알면 됩니다. ```js -let article = /* fetch new content from server */ +let article = /* 서버에서 새 콘텐츠를 가져옴 */ articleElem.innerHTML = article; ``` -The new `article` HTML may contain code snippets. We need to call `Prism.highlightElem` on them, otherwise they won't get highlighted. +새로 받아온 `article` HTML엔 코드 예시가 들어 있을 수 있습니다. `Prism.highlightElem`을 호출하지 않으면 이 코드는 강조 표시되지 않습니다. -**Where and when to call `Prism.highlightElem` for a dynamically loaded article?** +**동적으로 불러온 글엔 `Prism.highlightElem`을 어디서, 언제 호출해야 할까요?** -We could append that call to the code that loads an article, like this: +다음처럼 글을 불러오는 코드 뒤에 호출을 덧붙일 수 있습니다. ```js -let article = /* fetch new content from server */ +let article = /* 서버에서 새 콘텐츠를 가져옴 */ articleElem.innerHTML = article; *!* @@ -162,38 +162,38 @@ snippets.forEach(Prism.highlightElem); */!* ``` -...But, imagine if we have many places in the code where we load our content - articles, quizzes, forum posts, etc. Do we need to put the highlighting call everywhere, to highlight the code in content after loading? That's not very convenient. +...그런데 글, 퀴즈, 게시판 글처럼 콘텐츠를 불러오는 곳이 코드 곳곳에 많다고 상상해 봅시다. 불러온 콘텐츠 속 코드를 강조 표시하려고 호출 코드를 모든 곳에 붙여야 할까요? 그다지 편리한 방법이 아닙니다. -And what if the content is loaded by a third-party module? For example, we have a forum written by someone else, that loads content dynamically, and we'd like to add syntax highlighting to it. No one likes patching third-party scripts. +콘텐츠를 서드파티 모듈이 불러온다면 어떨까요? 예를 들어 다른 사람이 만든 게시판이 콘텐츠를 동적으로 불러오는데 여기에 구문 강조를 적용하고 싶을 수 있습니다. 서드파티 스크립트에 패치를 덧대는 일은 누구도 반기지 않습니다. -Luckily, there's another option. +다행히 다른 방법이 있습니다. -We can use `MutationObserver` to automatically detect when code snippets are inserted into the page and highlight them. +`MutationObserver`를 사용하면 코드 예시가 페이지에 삽입되는 순간을 자동으로 감지해 강조 표시할 수 있습니다. -So we'll handle the highlighting functionality in one place, relieving us from the need to integrate it. +이렇게 하면 강조 기능을 한곳에서 처리할 수 있어 통합 작업을 일일이 할 필요가 없어집니다. -### Dynamic highlight demo +### 동적 구문 강조 데모 -Here's the working example. +동작하는 예시를 봅시다. -If you run this code, it starts observing the element below and highlighting any code snippets that appear there: +아래 코드를 실행하면 밑에 있는 요소를 관찰하기 시작해서 그곳에 나타나는 코드 예시를 강조 표시합니다. ```js run let observer = new MutationObserver(mutations => { for(let mutation of mutations) { - // examine new nodes, is there anything to highlight? + // 새 노드를 검사합니다. 강조 표시할 대상이 있을까요? for(let node of mutation.addedNodes) { - // we track only elements, skip other nodes (e.g. text nodes) + // 요소만 추적하고 다른 노드(예: 텍스트 노드)는 건너뜁니다. if (!(node instanceof HTMLElement)) continue; - // check the inserted element for being a code snippet + // 삽입된 요소가 코드 예시인지 확인합니다. if (node.matches('pre[class*="language-"]')) { Prism.highlightElement(node); } - // or maybe there's a code snippet somewhere in its subtree? + // 서브트리 어딘가에 코드 예시가 있을 수도 있습니다. for(let elem of node.querySelectorAll('pre[class*="language-"]')) { Prism.highlightElement(elem); } @@ -207,67 +207,67 @@ let demoElem = document.getElementById('highlight-demo'); observer.observe(demoElem, {childList: true, subtree: true}); ``` -Here, below, there's an HTML-element and JavaScript that dynamically fills it using `innerHTML`. +바로 아래에 HTML 요소가 하나 있고 `innerHTML`을 사용해 이 요소를 동적으로 채우는 자바스크립트가 있습니다. -Please run the previous code (above, observes that element), and then the code below. You'll see how `MutationObserver` detects and highlights the snippet. +먼저 위 코드(해당 요소를 관찰함)를 실행한 다음 아래 코드를 실행해 보세요. `MutationObserver`가 코드 예시를 감지해 강조 표시하는 모습을 볼 수 있습니다. -

A demo-element with id="highlight-demo", run the code above to observe it.

+

id="highlight-demo"가 붙은 데모 요소입니다. 위 코드를 실행해 이 요소를 관찰해 보세요.

-The following code populates its `innerHTML`, that causes the `MutationObserver` to react and highlight its contents: +아래 코드가 `innerHTML`을 채우면 `MutationObserver`가 반응해 내용을 강조 표시합니다. ```js run let demoElem = document.getElementById('highlight-demo'); -// dynamically insert content with code snippets -demoElem.innerHTML = `A code snippet is below: +// 코드 예시가 담긴 콘텐츠를 동적으로 삽입합니다. +demoElem.innerHTML = `아래는 코드 예시입니다.
 let hello = "world!"; 
-
Another one:
+
예시가 하나 더 있습니다.
.class { margin: 5px; } 
`; ``` -Now we have `MutationObserver` that can track all highlighting in observed elements or the whole `document`. We can add/remove code snippets in HTML without thinking about it. +이제 관찰 대상 요소나 `document` 전체에서 일어나는 강조 표시를 `MutationObserver`가 전부 추적합니다. 별다른 신경을 쓰지 않아도 HTML에 코드 예시를 추가하거나 삭제할 수 있게 되었죠. -## Additional methods +## 기타 메서드 -There's a method to stop observing the node: +노드 관찰을 중단하는 메서드가 있습니다. -- `observer.disconnect()` -- stops the observation. +- `observer.disconnect()` -- 관찰을 중단함 -When we stop the observing, it might be possible that some changes were not yet processed by the observer. In such cases, we use +관찰을 중단하는 시점에 옵저버가 아직 처리하지 않은 변경이 남아 있을 수 있습니다. 이럴 땐 다음 메서드를 사용합니다. -- `observer.takeRecords()` -- gets a list of unprocessed mutation records - those that happened, but the callback has not handled them. +- `observer.takeRecords()` -- 처리되지 않은 뮤테이션 레코드 목록을 가져옴. 변경은 일어났지만 콜백이 아직 처리하지 않은 레코드가 대상임 -These methods can be used together, like this: +두 메서드는 다음처럼 함께 쓸 수 있습니다. ```js -// get a list of unprocessed mutations -// should be called before disconnecting, -// if you care about possibly unhandled recent mutations +// 처리되지 않은 뮤테이션 목록을 가져옵니다. +// 최근 일어난 변경 중 미처리분까지 챙기려면 +// 관찰을 중단하기 전에 호출해야 합니다. let mutationRecords = observer.takeRecords(); -// stop tracking changes +// 변경 추적을 중단합니다. observer.disconnect(); ... ``` -```smart header="Records returned by `observer.takeRecords()` are removed from the processing queue" -The callback won't be called for records, returned by `observer.takeRecords()`. +```smart header="`observer.takeRecords()`가 반환한 레코드는 처리 대기열에서 제거됩니다" +`observer.takeRecords()`가 반환한 레코드에 대해선 콜백이 호출되지 않습니다. ``` -```smart header="Garbage collection interaction" -Observers use weak references to nodes internally. That is, if a node is removed from the DOM, and becomes unreachable, then it can be garbage collected. +```smart header="가비지 컬렉션과의 상호작용" +옵저버는 내부적으로 노드에 대해 약한 참조(weak reference)를 사용합니다. 따라서 노드가 DOM에서 제거되어 도달할 수 없게 되면 가비지 컬렉션의 대상이 됩니다. -The mere fact that a DOM node is observed doesn't prevent the garbage collection. +DOM 노드가 관찰되고 있다는 사실만으로는 가비지 컬렉션이 막히지 않습니다. ``` -## Summary +## 요약 -`MutationObserver` can react to changes in DOM - attributes, text content and adding/removing elements. +`MutationObserver`는 DOM에서 일어나는 변경(속성, 텍스트 콘텐츠, 요소 추가·삭제)에 반응할 수 있습니다. -We can use it to track changes introduced by other parts of our code, as well as to integrate with third-party scripts. +코드의 다른 부분에서 일어난 변경을 추적할 때는 물론 서드파티 스크립트와 통합할 때도 사용할 수 있습니다. -`MutationObserver` can track any changes. The config "what to observe" options are used for optimizations, not to spend resources on unneeded callback invocations. +`MutationObserver`는 어떤 변경이든 추적할 수 있습니다. '무엇을 관찰할지' 정하는 config 옵션은 최적화 용도로, 불필요한 콜백 호출에 자원을 낭비하지 않기 위해 사용합니다. From 3ced6b2d227df4f1b727a5af1724fd4384959097 Mon Sep 17 00:00:00 2001 From: Bora Lee Date: Sun, 19 Jul 2026 02:11:14 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[=EB=AE=A4=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=98=B5=EC=A0=80=EB=B2=84]=20=ED=91=9C=ED=98=84=20=EB=8B=A4?= =?UTF-8?q?=EB=93=AC=EA=B8=B0=EC=99=80=20=EB=A7=9E=EC=B6=A4=EB=B2=95=20?= =?UTF-8?q?=EA=B5=90=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Ezn3Dq7aWbVPvWonrUn8YK --- .../01-mutation-observer/article.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/2-ui/99-ui-misc/01-mutation-observer/article.md b/2-ui/99-ui-misc/01-mutation-observer/article.md index 96d7d77047..40b6b5e872 100644 --- a/2-ui/99-ui-misc/01-mutation-observer/article.md +++ b/2-ui/99-ui-misc/01-mutation-observer/article.md @@ -7,7 +7,7 @@ ## 문법 -`MutationObserver`는 사용법이 간단합니다. +`MutationObserver` 사용법은 간단합니다. 먼저 콜백 함수를 넘겨 옵저버를 만듭니다. @@ -32,7 +32,7 @@ observer.observe(node, config); - `attributeOldValue` -- `true`이면 속성의 이전 값과 새 값을 모두 콜백에 전달하고(아래 참고) 그렇지 않으면 새 값만 전달함(`attributes` 옵션 필요) - `characterDataOldValue` -- `true`이면 `node.data`의 이전 값과 새 값을 모두 콜백에 전달하고(아래 참고) 그렇지 않으면 새 값만 전달함(`characterData` 옵션 필요) -이후 변경이 생길 때마다 `callback`이 실행됩니다. 이때 첫 번째 인수로 [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) 객체 목록이, 두 번째 인수로 옵저버 자신이 전달됩니다. +실제 변경이 생길 때마다 `callback`이 실행됩니다. 이때 콜백 함수의 첫 번째 인수로 [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) 객체 목록이, 두 번째 인수로 옵저버 자신이 전달됩니다. [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) 객체에는 다음과 같은 프로퍼티가 있습니다. @@ -65,7 +65,7 @@ observer.observe(elem, { ``` -위 코드를 브라우저에서 실행하고 `
`에 포커스를 준 다음 `수정` 안의 텍스트를 바꾸면 `console.log`에 뮤테이션 하나가 출력됩니다. +우측 상단 재생 버튼을 눌러 코드를 브라우저에서 실행하고 `
`에 포커스를 준 다음 `수정` 안의 텍스트를 바꾸면 `console.log` 때문에 개발자 도구에 뮤테이션 하나가 출력됩니다. ```js mutationRecords = [{ @@ -76,7 +76,7 @@ mutationRecords = [{ }]; ``` -`수정`을 통째로 지우는 등 더 복잡하게 수정하면 뮤테이션 이벤트에 뮤테이션 레코드가 여러 개 담길 수 있습니다. +`수정`을 통째로 지우는 등 더 복잡한 방식으로 수정을 하면 뮤테이션 이벤트에 뮤테이션 레코드가 여러 개 담길 수 있습니다. ```js mutationRecords = [{ @@ -103,9 +103,9 @@ mutationRecords = [{ 유용한 기능이 들어 있지만 원치 않는 동작도 하는 서드파티 스크립트를 추가해야 하는 상황을 상상해 봅시다. 이 스크립트는 `
원치 않는 광고
`같이 광고를 노출합니다. -당연하게도 서드파티 스크립트엔 광고를 제거할 수단이 없습니다. +당연하게도 서드파티 스크립트는 광고를 제거할 수단을 제공하지 않습니다. -`MutationObserver`를 사용하면 원치 않는 요소가 DOM에 나타나는 순간을 감지해 제거할 수 있습니다. +이럴 때 `MutationObserver`를 사용하면 원치 않는 요소가 DOM에 나타나는 순간을 감지해 제거할 수 있습니다. 이 외에도 서드파티 스크립트가 문서에 무언가를 추가하는 시점을 감지해서 페이지를 조정하거나 특정 영역의 크기를 동적으로 조절하고 싶은 경우도 있습니다. @@ -128,7 +128,7 @@ mutationRecords = [{ ... ``` -가독성을 높이는 동시에 보기 좋게 꾸미기 위해 [Prism.js](https://prismjs.com/) 같은 자바스크립트 구문 강조(syntax highlighting) 라이브러리를 사이트에 사용해 보겠습니다. Prism에서 위 예시에 구문 강조를 적용하려면 `Prism.highlightElem(pre)`를 호출합니다. 이 메서드는 `pre` 요소의 내용을 검사해서 색을 입히는 특별한 태그와 스타일을 해당 요소 안에 추가합니다. 지금 보고 있는 이 페이지의 예시와 비슷한 결과물이 만들어지죠. +가독성을 높이는 동시에 보기 좋게 꾸미기 위해 [Prism.js](https://prismjs.com/) 같은 자바스크립트 구문 강조(syntax highlighting) 라이브러리를 사이트에 사용해 본다고 가정하겠습니다. Prism에서 위 예시에 구문 강조를 적용하려면 `Prism.highlightElem(pre)`를 호출합니다. 이 메서드는 `pre` 요소의 내용을 검사해서 색을 입히는 특별한 태그와 스타일을 해당 요소 안에 추가합니다. 지금 보고 있는 이 페이지의 예시 코드와 비슷한 결과물이 만들어지죠. 그렇다면 구문 강조 메서드는 정확히 언제 실행해야 할까요? `DOMContentLoaded` 이벤트에서 실행할 수도 있고 스크립트를 페이지 맨 아래에 넣을 수도 있습니다. DOM이 준비되면 `pre[class*="language"]`에 해당하는 요소를 찾아 `Prism.highlightElem`을 호출하면 됩니다. @@ -148,9 +148,9 @@ articleElem.innerHTML = article; 새로 받아온 `article` HTML엔 코드 예시가 들어 있을 수 있습니다. `Prism.highlightElem`을 호출하지 않으면 이 코드는 강조 표시되지 않습니다. -**동적으로 불러온 글엔 `Prism.highlightElem`을 어디서, 언제 호출해야 할까요?** +**그럼 동적으로 불러온 글엔 `Prism.highlightElem`을 어디서, 언제 호출해야 할까요?** -다음처럼 글을 불러오는 코드 뒤에 호출을 덧붙일 수 있습니다. +다음처럼 글을 불러오는 코드 뒤에 호출을 덧붙일 수 있을 겁니다. ```js let article = /* 서버에서 새 콘텐츠를 가져옴 */ @@ -162,7 +162,7 @@ snippets.forEach(Prism.highlightElem); */!* ``` -...그런데 글, 퀴즈, 게시판 글처럼 콘텐츠를 불러오는 곳이 코드 곳곳에 많다고 상상해 봅시다. 불러온 콘텐츠 속 코드를 강조 표시하려고 호출 코드를 모든 곳에 붙여야 할까요? 그다지 편리한 방법이 아닙니다. +그런데 글, 퀴즈, 게시판 글처럼 콘텐츠를 불러오는 곳이 코드 곳곳에 많다고 상상해 봅시다. 불러온 콘텐츠 속 코드를 강조 표시하려고 위와 같은 코드를 모든 곳에 붙여야 할까요? 그다지 편리한 방법이 아닙니다. 콘텐츠를 서드파티 모듈이 불러온다면 어떨까요? 예를 들어 다른 사람이 만든 게시판이 콘텐츠를 동적으로 불러오는데 여기에 구문 강조를 적용하고 싶을 수 있습니다. 서드파티 스크립트에 패치를 덧대는 일은 누구도 반기지 않습니다. @@ -176,16 +176,16 @@ snippets.forEach(Prism.highlightElem); 동작하는 예시를 봅시다. -아래 코드를 실행하면 밑에 있는 요소를 관찰하기 시작해서 그곳에 나타나는 코드 예시를 강조 표시합니다. +아래 코드를 실행하면 하위 요소를 관찰하기 시작해서 그곳에 나타나는 코드 예시를 강조 표시합니다. ```js run let observer = new MutationObserver(mutations => { for(let mutation of mutations) { - // 새 노드를 검사합니다. 강조 표시할 대상이 있을까요? + // 강조 표시할 새 노드가 있는지 검사합니다. for(let node of mutation.addedNodes) { - // 요소만 추적하고 다른 노드(예: 텍스트 노드)는 건너뜁니다. + // 요소(노드)만 추적하고 다른 노드(예: 텍스트 노드)는 건너뜁니다. if (!(node instanceof HTMLElement)) continue; // 삽입된 요소가 코드 예시인지 확인합니다. @@ -193,7 +193,7 @@ let observer = new MutationObserver(mutations => { Prism.highlightElement(node); } - // 서브트리 어딘가에 코드 예시가 있을 수도 있습니다. + // 서브트리 어딘가에 코드 예시가 있을 수 있으니 확인합니다. for(let elem of node.querySelectorAll('pre[class*="language-"]')) { Prism.highlightElement(elem); } @@ -209,7 +209,7 @@ observer.observe(demoElem, {childList: true, subtree: true}); 바로 아래에 HTML 요소가 하나 있고 `innerHTML`을 사용해 이 요소를 동적으로 채우는 자바스크립트가 있습니다. -먼저 위 코드(해당 요소를 관찰함)를 실행한 다음 아래 코드를 실행해 보세요. `MutationObserver`가 코드 예시를 감지해 강조 표시하는 모습을 볼 수 있습니다. +먼저 위 코드(해당 요소를 관찰함)를 실행한 다음 아래쪽 코드를 실행해 보세요. `MutationObserver`가 코드만 찾아내 강조 표시하는 모습을 볼 수 있습니다.

id="highlight-demo"가 붙은 데모 요소입니다. 위 코드를 실행해 이 요소를 관찰해 보세요.

@@ -228,11 +228,11 @@ demoElem.innerHTML = `아래는 코드 예시입니다. `; ``` -이제 관찰 대상 요소나 `document` 전체에서 일어나는 강조 표시를 `MutationObserver`가 전부 추적합니다. 별다른 신경을 쓰지 않아도 HTML에 코드 예시를 추가하거나 삭제할 수 있게 되었죠. +이제 관찰 대상 요소나 `document` 전체에서 일어나는 강조 표시를 `MutationObserver`가 전부 추적할 수 있게 되었습니다. 별다른 신경을 쓰지 않아도 HTML에 코드 예시가 추가되거나 삭제되어도 알아서 강조 표시가 됩니다. ## 기타 메서드 -노드 관찰을 중단하는 메서드가 있습니다. +노드 관찰을 중단하는 메서드도 존재합니다. - `observer.disconnect()` -- 관찰을 중단함 @@ -245,7 +245,7 @@ demoElem.innerHTML = `아래는 코드 예시입니다. ```js // 처리되지 않은 뮤테이션 목록을 가져옵니다. // 최근 일어난 변경 중 미처리분까지 챙기려면 -// 관찰을 중단하기 전에 호출해야 합니다. +// 관찰을 중단하기 전에 takeRecords를 호출해야 합니다. let mutationRecords = observer.takeRecords(); // 변경 추적을 중단합니다.