diff options
Diffstat (limited to 'files/ko')
-rw-r--r-- | files/ko/web/api/eventtarget/addeventlistener/index.md | 748 | ||||
-rw-r--r-- | files/ko/web/api/eventtarget/dispatchevent/index.md | 57 | ||||
-rw-r--r-- | files/ko/web/api/eventtarget/eventtarget/index.md | 44 | ||||
-rw-r--r-- | files/ko/web/api/eventtarget/index.md | 9 | ||||
-rw-r--r-- | files/ko/web/api/eventtarget/removeeventlistener/index.md | 204 |
5 files changed, 524 insertions, 538 deletions
diff --git a/files/ko/web/api/eventtarget/addeventlistener/index.md b/files/ko/web/api/eventtarget/addeventlistener/index.md index 2e128fa3b5..71cc06a1ee 100644 --- a/files/ko/web/api/eventtarget/addeventlistener/index.md +++ b/files/ko/web/api/eventtarget/addeventlistener/index.md @@ -2,114 +2,157 @@ title: EventTarget.addEventListener() slug: Web/API/EventTarget/addEventListener tags: - - API - - DOM - - Event Handlers - - Event Listener - - EventTarget - - JavaScript - Method - Reference +browser-compat: api.EventTarget.addEventListener translation_of: Web/API/EventTarget/addEventListener --- -{{APIRef("DOM Events")}} +{{APIRef("DOM")}} -{{domxref("EventTarget")}}의 **`addEventListener()`** 메서드는 지정한 이벤트가 대상에 전달될 때마다 호출할 함수를 설정합니다. 일반적인 대상은 {{domxref("Element")}}, {{domxref("Document")}}, {{domxref("Window")}}지만, {{domxref("XMLHttpRequest")}}와 같이 이벤트를 지원하는 모든 객체를 대상으로 지정할 수 있습니다. +{{domxref("EventTarget")}} 인터페이스의 **`addEventListener()`** 메서드는 지정한 유형의 이벤트를 대상이 수신할 때마다 호출할 함수를 설정합니다. -`addEventListener()`는 {{domxref("EventTarget")}}의 주어진 이벤트 유형에, {{domxref("EventListener")}}를 구현한 함수 또는 객체를 이벤트 처리기 목록에 추가해 작동합니다. +일반적인 대상은 {{domxref("Element")}}, {{domxref("Document")}}, {{domxref("Window")}}지만, {{domxref("XMLHttpRequest")}}와 같이 이벤트를 지원하는 모든 객체가 대상이 될 수 있습니다. + +> **참고:** 이벤트 수신기는 다른 방법으로도 추가할 수 있지만, `addEventListener()` 메서드를 사용해서 다음의 장점을 누리는 것이 좋습니다. +> - 하나의 이벤트 유형에 대해 다수의 수신기를 부착할 수 있습니다. 라이브러리, JavaScript 모듈 등, 다른 라이브러리나 확장 코드와 충돌하지 않고 동작해야 하는 코드에 특히 중요한 점입니다. +> - `onXYZ` 속성과 달리, 수신기가 어떤 이벤트 전파 단계(캡처링 vs. 버블링)에 동작해야 하는지 조절할 수 있습니다. +> - HTML과 SVG 요소가 아니어도 이벤트 대상이라면 사용할 수 있습니다. + +`addEventListener()` 메서드는 지정한 이벤트 유형의{{domxref("EventTarget")}} 수신기 리스트에 {{domxref("EventListener")}}를 구현한 함수 또는 객체를 추가하는 방식으로 동작합니다. 추가하려는 함수 또는 객체가 이미 수신기 리스트에 포함되어 있는 경우에는 추가하지 않으므로 수신기는 중복으로 등록되지 않습니다. + +추가한 수신기를 반드시 {{domxref("EventTarget.removeEventListener", "removeEventListener()")}}로 직접 제거해야 하는 것은 아닙니다. + +> **참고:** 두 개의 익명 함수는, 함수 본문이 동일하더라도, `addEventListener()`에 있어 항상 서로 다른 함수로 취급되므로 둘을 동시에 한 대상의 이벤트 수신기로 부착할 수 있습니다. +> +> 사실, 본문의 내용이 항상 동일하고 불변하더라도, 그 본문을 사용해 정의하는 각각의 익명 함수는 항상 서로를 구별할 수 있는 별도의 함수입니다. **반복문 내에서 정의하는 경우에도 마찬가지입니다.** +> +> 이와 같이 반복적으로 익명 함수를 정의하게 되면 문제가 될 수 있습니다. 아래의 [메모리 문제](#메모리_문제)를 확인하세요. + +{{domxref("EventTarget")}}에 부착된 이벤트 수신기가 이벤트 처리 중에 새로운 수신기를 등록하더라도, 현재 처리 중인 이벤트로는 그 수신기가 발동하지 않습니다. 그러나 버블링 단계처럼 이후의 이벤트 처리 흐름에서는 발동할 수 있습니다. ## 구문 - target.addEventListener(type, listener[, options]); - target.addEventListener(type, listener[, useCapture]); - target.addEventListener(type, listener[, useCapture, wantsUntrusted {{Non-standard_inline}}]); // Gecko/Mozilla only +```js +addEventListener(type, listener); +addEventListener(type, listener, options); +addEventListener(type, listener, useCapture); +``` ### 매개변수 -<dl><dt><code>type</code></dt><dd>반응할 <a href="/ko/docs/Web/Events">이벤트 유형</a>을 나타내는 대소문자 구분 문자열.</dd><dt><code>listener</code></dt><dd>지정된 타입의 이벤트가 발생했을 때, 알림({{domxref("Event")}} 인터페이스를 구현하는 객체)을 받는 객체입니다. {{domxref("EventListener")}} 인터페이스 또는 JavaScript <a href="/en-US/docs/JavaScript/Guide/Functions">function</a>를 구현하는 객체여야만 합니다. 콜백 자체에 대한 자세한 내용은 {{anch("The event listener callback")}} 를 참조하세요.</dd><dt><code>options</code> {{optional_inline}}</dt><dd>이벤트 리스너에 대한 특성을 지정하는 옵션 객체입니다. 사용 가능한 옵션은 다음과 같습니다 :<ul><li><code>capture</code>: DOM 트리의 하단에 있는 <code>EventTarget</code> 으로 전송하기 전에, 등록된 <code>listener</code> 로 이 타입의 이벤트의 전송여부를 나타내는 {{jsxref("Boolean")}} 입니다.</li><li><code>once</code>: 리스너를 추가한 후 한 번만 호출되어야 함을 나타내는 {{jsxref("Boolean")}}입니다. <code>true</code>이면 호출할 때 <code>listener</code> 가 자동으로 삭제됩니다.</li><li><code>passive</code>: <code>true</code>일 경우, <code>listener</code>에서 지정한 함수가 {{domxref("Event.preventDefault", "preventDefault()")}}를 호출하지 않음을 나타내는 {{jsxref("Boolean")}}입니다. passive listener 가 <code>preventDefault()</code>를 호출하면 user agent는 콘솔 경고를 생성하는 것 외의 작업은 수행하지 않습니다. 자세한 내용은 {{anch("Improving scrolling performance with passive listeners")}} 를 참조하세요.</li><li>{{non-standard_inline}} <code>mozSystemGroup</code>: listener를 시스템 그룹에 추가해야함을 나타내는 {{jsxref("Boolean")}} 입니다. 오직 XBL 혹은 파이어폭스 브라우저의 {{glossary("chrome")}}에서 실행되는 코드에서만 사용할 수 있습니다.</li></ul></dd><dt><code>useCapture</code> {{optional_inline}}</dt><dd>DOM 트리의 하단에 있는 <code>EventTarget</code> 으로 전송하기 전에, 등록된 <code>listener</code> 로 이 타입의 이벤트의 전송여부를 나타내는 {{jsxref("Boolean")}} 입니다. 트리에서 위쪽으로 버블링되는 이벤트는 캡처를 사용하도록, 지정된 listener를 트리거하지 않습니다. 이벤트 버블링과 캡쳐는 두 요소(엘리먼트)가 해당 이벤트에 대한 핸들(함수)를 등록한 경우, 다른 요소 내에 중첩된 요소에서 발생하는 이벤트를 전파하는 두 가지 방법 입니다. 이벤트 전파 모드는 요소가 이벤트를 수신하는 순서를 판별합니다. 자세한 설명은 <a href="http://www.w3.org/TR/DOM-Level-3-Events/#event-flow">DOM Level 3 Events</a> 과 <a href="http://www.quirksmode.org/js/events_order.html#link4">JavaScript Event order</a> 를 참조하세요. 값을 지정하지 않으면, <code>useCapture</code> 의 기본값은 <code>false</code> 입니다.</dd><dd><div class="note"><strong>참고:</strong> 이벤트 타겟에 연결된 이벤트 리스너의 경우, 이벤트는 캡쳐링과 버블링 단계가 아니라 타겟 단계에 있습니다. 타겟 단계의 이벤트는 <code>useCapture</code> 매개변수(파라미터)와 상관없이, 그들이 등록된 순서대로 요소의 모든 리스너를 트리거합니다.</div><div class="note"><strong>참고:</strong> <code>useCapture</code> 가 항상 선택사항인 것은 아닙니다. 가장 광범위한 브라우저 호환성을 위해 포함시키는 것이 좋습니다.</div></dd><dt><code>wantsUntrusted</code> {{Non-standard_inline}}</dt><dd>파이어폭스(겍코) 명세의 매개변수 입니다. <code>true</code>의 경우, 리스너는 웹 컨텐츠에 의해 dispatch되는 합성 이벤트를 수신합니다. (기본값은 {{glossary("chrome")}} 브라우저의 경우 <code>false</code> , 보통의 웹 페이지에서는 <code>true</code>입니다.) 이 매개 변수는 브라우저 자체 뿐만 아니라, 에드온에게도 유용합니다.</dd></dl> +- `type` + - : 수신할 [이벤트 유형](/ko/docs/Web/Events)을 나타내는 대소문자 구분 문자열입니다. +- `listener` + - : 지정한 이벤트({{domxref("Event")}} 인터페이스를 구현한 객체)를 수신할 객체입니다. {{domxref("EventListener")}} 인터페이스를 구현하는 객체거나, JavaScript [함수](/ko/docs/Web/JavaScript/Guide/Functions)여야 합니다. [이벤트 수신기 콜백](#이벤트_수신기_콜백)에서 콜백 자체에 대한 정보를 더 알아보세요. +- `options` {{optional_inline}} + - : 이벤트 수신기의 특징을 지정할 수 있는 객체입니다. 가능한 옵션은 다음과 같습니다. + - `capture` + - : 이벤트 대상의 DOM 트리 하위에 위치한 자손 `EventTarget`으로 이벤트가 전달되기 전에, 이 수신기가 먼저 발동돼야 함을 나타내는 불리언 값입니다. + - `once` + - : 수신기가 최대 한 번만 동작해야 함을 나타내는 불리언 값입니다. `true`를 지정할 경우, 수신기가 발동한 후에 스스로를 대상에서 제거합니다. + - `passive` + - : `true`일 경우, 이 수신기 내에서 절대 {{domxref("Event.preventDefault", "preventDefault()")}}를 호출하지 않을 것임을 나타내는 불리언 값입니다. 이 값이 `true`인데 수신기가 `preventDefault()`를 호출하는 경우, 사용자 에이전트는 콘솔에 경고를 출력하는 것 외에 아무런 동작도 하지 않습니다. [패시브 수신기로 스크롤 성능 향상](#패시브_수신기로_스크롤_성능_향상)에서 이 값에 대해 더 알아보세요. + - `signal` + - : {{domxref("AbortSignal")}}입니다. 지정한 `AbortSignal` 객체의 {{domxref("AbortController.abort", "abort()")}} 메서드를 호출하면 이 수신기가 제거됩니다. + +- `useCapture` {{optional_inline}} + + - : 이벤트 대상의 DOM 트리 하위에 위치한 자손 `EventTarget`으로 이벤트가 전달되기 전에, 이 수신기가 먼저 발동돼야 함을 나타내는 불리언 값입니다. 캡처 모드인 수신기는 DOM 트리의 위쪽으로 버블링 중인 이벤트에 의해선 발동하지 않습니다. 이벤트 버블링과 캡처링은 조상-자손 관계를 가진 두 개의 요소가 동일한 이벤트 유형에 대한 수신기를 가지고 있을 때, 두 요소에 이벤트가 전파되는 방법을 말합니다. 이벤트 전파 모드에 따라 두 요소 중 이벤트를 먼저 수신하는 쪽이 달라집니다. [DOM Level 3 Events](https://www.w3.org/TR/DOM-Level-3-Events/#event-flow)와 [JavaScript Event 순서](https://www.quirksmode.org/js/events_order.html#link4)에서 자세한 설명을 확인하세요. 기본 값은 `false`입니다. + + > **참고:** 이벤트의 대상에 부착된 수신기의 경우 캡처링도, 버블링 단계도 아닌 별도의 단계에 발동합니다. + > 캡처 모드의 수신기는 캡처 모드가 아닌 다른 모든 수신기보다 앞서 발동합니다. + +- `wantsUntrusted` {{optional_inline}} {{Non-standard_inline}} + - : Firefox(Gecko)에서만 사용할 수 있습니다. `true`일 경우 수신기가 웹 콘텐츠에서 발송하는 합성 이벤트를 수신할 수 있습니다. (기본 값은 브라우저 {{glossary("chrome", "크롬")}}에서는 `false`, 일반 웹 페이지에서는 `true`입니다.) 브라우저 확장, 또는 브라우저 자체 코드에서 유용하게 사용할 수 있습니다. + +### 반환 값 + +없음. -## Usage notes +## 사용 일람 -### 이벤트 리스너 콜백 +### 이벤트 수신기 콜백 -이벤트 리스너는 콜백 함수로 지정할 수 있습니다. 또는 {{domxref("EventListener.handleEvent", "handleEvent()")}} 메서드가 콜백 함수 역할을 하는 {{domxref("EventListener")}}를 구현하는 객체로 지정할 수 있습니다. +`addEventListener()`에 지정하는 이벤트 수신기는 콜백 함수거나, (콜백으로 작동할 {{domxref("EventListener.handleEvent", "handleEvent()")}} 메서드를 가진) {{domxref("EventListener")}} 인터페이스를 구현하는 객체입니다. -콜백 함수 자체는 `handleEvent()` 메서드와 동일한 매개 변수와 반환값을 가집니다. 즉, 콜백은 단일 매개 변수를 허용합니다: 발생한 이벤트를 설명하는 {{domxref("Event")}}에 기반한 객체이며, 아무것도 반환하지 않습니다. +콜백 함수 자체는 `handleEvent()` 메서드와 같은 매개변수, 같은 반환 값을 가집니다. 즉, 콜백 함수는 발생한 이벤트를 설명하는 {{domxref("Event")}} 기반 객체를 유일한 매개변수로 받고, 아무것도 반환하지 않습니다. -예를들어 {{event("fullscreenchange")}} 와 {{event("fullscreenerror")}}를 처리하는데 사용할 수 있는 이벤트 핸들러 콜백은 다음과 같습니다: +다음은 {{event("fullscreenchange")}}와 {{event("fullscreenerror")}} 두 유형의 이벤트를 동시에 처리할 수 있는 이벤트 처리 콜백의 예제입니다. ```js function eventHandler(event) { if (event.type == 'fullscreenchange') { - /* handle a full screen toggle */ + /* 전체화면 여부 변화 처리 */ } else /* fullscreenerror */ { - /* handle a full screen toggle error */ + /* 전체화면 오류 처리 */ } } ``` -### 옵션 지원을 안전하게 감지 +### 옵션 지원을 안전하게 감지하기 -이전 버전의 DOM 명세에선, `addEventListener()`의 세 번째 매개 변수는 캡쳐의 사용여부를 나타내는 Boolean값 이었습니다. 시간이 지남에 따라 더 많은 옵션이 필요하다는 것이 분명 해졌습니다. 함수에 매개 변수를 추가하는 대신 (옵션값을 처리할 때 엄청나게 복잡한 작업), 세 번째 매개 변수는 다양한 속성을 포함 할 수 있는 객체로 변경되었습니다. 이 객체는 이벤트 리스너를 제거하는 프로세스를 구성하는 옵션값을 정의할 수 있습니다. +과거 DOM 명세에선 `addEventListener()`의 세 번째 매개 변수가 캡처 여부를 나타내는 불리언 값이었습니다. 그러나 시간이 지남에 따라 더 많은 옵션이 필요하다는 것이 분명해졌습니다. 메서드 매개변수를 계속 늘리면 선택적인 옵션을 나타내는 매개변수 처리가 어려워질 것이므로, 이제 세 번째 매개변수는 불리언 값이 아니라 이벤트 수신기의 다양한 성질을 설명하는 옵션 객체가 됐습니다. -지난 버전의 브라우저(뿐만 아니라 너무 오래된 브라우저)에서는 여전히 세 번째 매개 변수가 Boolean 이라고 가정하고 시나리오를 지능적으로 처리할 코드를 작성해야 합니다. 관심있는 각 옵션에 대해 기능 감지를 사용하여 이 작업을 수행할 수 있습니다. +구형 브라우저에서는 (그리고 일부 상대적으로 덜 오래된 브라우저에서도) 여전히 세 번째 매개변수에 오로지 불리언 값만 기대하고 있으므로 브라우저간 차이점을 처리할 수 있는 코드를 작성할 필요가 있습니다. 필요한 옵션에 대한 기능 감지 코드를 사용하세요. -예를들어서, `passive` 옵션을 확인하려면 다음과 같이 하세요 : +예를 들어, `passive` 옵션의 지원 여부를 알아보고 싶다고 가정하겠습니다. - var passiveSupported = false; - - try { - var options = { - get passive() { // This function will be called when the browser - // attempts to access the passive property. - passiveSupported = true; - } - }; +```js +let passiveSupported = false; - window.addEventListener("test", options, options); - window.removeEventListener("test", options, options); - } catch(err) { - passiveSupported = false; +try { + const options = { + get passive() { // 브라우저가 passive 속성에 접근하려고 하면 이 함수가 실행됨 + passiveSupported = true; + return false; } + }; + + window.addEventListener("test", null, options); + window.removeEventListener("test", null, options); +} catch(err) { + passiveSupported = false; +} +``` -이렇게 하면 `passive` 속성(프로퍼티)에 대한 getter함수를 사용하여 `options` 객체가 만들어집니다; get을 호출 할 경우 gtter는 플래그 `passiveSupported`를 `true`로 설정합니다. 즉, 브라우저가 `options` 객체의 `passive` 속성 값을 검사하면 `passiveSupported`가 `true`로 설정됩니다; 그렇지 않으면 `false`가 유지됩니다. 그리고 `addEventListener()`를 호출하여 가짜 이벤트 핸들러를 설정합니다. 해당 옵션을 지정하여 브라우저가 객체를 세 번째 매개 변수로 인식하면 옵션을 확인합니다. 그런 다음 `removeEventListener()` 를 호출하여 스스로 정리합니다. (`handleEvent()`는 호출되지 않은 이벤트 리스너에서는 무시됩니다.) +위의 코드는 `passive` 속성에 대한 접근자 함수를 가진 `options` 객체를 생성하고, `passive` 접근자는 자신이 호출되는 순간 `passiveSupported` 플래그 변수를 `true`로 설정합니다. 이 말은, `passiveSupported`가 `true`라면 브라우저가 `options` 객체의 `passive` 속성을 확인한다는 뜻이고, `false`면 확인하지 않는다는 뜻입니다. 그 아래에서는 `addEventListener()`를 사용해 가짜 이벤트 처리기를 등록, 브라우저가 세 번째 매개변수 객체를 인식할 수 있는지 확인하고, `removeEventListener()`로 정리합니다. (이벤트 수신기는 발동할 일이 없으므로 `null`을 지정해도 무방합니다.) -이 방법으로 지원되는 옵션이 있는지 확인할 수 있습니다. 위와 비슷한 코드를 사용하여 해당 옵션에 대한 getter를 추가하기 만하면됩니다. +이 방법으로 모든 옵션에 대한 지원 여부를 확인할 수 있습니다. 위 코드와 비슷하게, 확인하려는 옵션에 대한 접근자를 추가하기만 하면 됩니다. -그런 다음 문제의 옵션을 사용하는 실제 이벤트 리스너를 만들려면 다음과 같이 쓸 수 있습니다: +그 후, 실제로 플래그를 사용할 땐 아래와 같이 할 수 있습니다. ```js someElement.addEventListener("mouseup", handleMouseUp, passiveSupported ? { passive: true } : false); ``` -여기에서는 {{event("mouseup")}} 이벤트에 대한 리스너를 `someElement`요소에 추가합니다. 새 번째 매개변수의 경우 `passiveSupported`가 `true`면, `options` 객체를 `passive` : `true` 로 설정합니다; 그렇지 않으면, 우리는 Boolean을 전달해야 함올 알고있습니다. `useCapture` 매개변수의 값으로 `false` 를 전달합니다. +위 코드에서는 {{event("mouseup")}} 이벤트에 대한 수신기를 `someElement` 요소에 추가하고 있습니다. 세 번째 매개변수를 살펴보면, 만약 `passiveSupported`가 `true`일 경우 `passive`를 `true`로 지정한 옵션 객체를 지정하고 있으며, `passiveSupported`가 `false`일 경우, 세 번째 매개변수는 불리언 값이어야 할 것이므로 `useCapture`에 대한 값인 `false`를 지정하는 모습입니다. -원하는 경우 [Modernizr](https://modernizr.com/docs) 혹은 [Detect It](https://github.com/rafrex/detect-it) 과 같은 서드파티 라이브러리를 사용하여 이러한 테스트를 수행할 수 있습니다. +직접 알아내는 대신 [Modernizr](https://modernizr.com/docs)나 [Detect It](https://github.com/rafrex/detect-it) 등 서드파티 라이브러리를 사용해 기능 감지를 할 수도 있습니다. -[Web Incubator Community Group](https://wicg.github.io/admin/charter.html)의 [`EventListenerOptions`](https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection)에 대한 기사에서 더 많은 것을 배울 수 있습니다. +[Web Incubator Community Group](https://wicg.github.io/admin/charter.html)의 [`EventListenerOptions`](https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection)에 대한 글에서 더 자세한 정보를 알아보세요. ## 예제 -### 간단한 리스너 추가 +### 간단한 수신기 추가하기 -이 예제는 `addEventListener()` 를 사용하여 요소에 대한 마우스 클릭을 감지하는 방법을 보여줍니다. +이 예제는 `addEventListener()`를 사용하여 요소에 대한 마우스 클릭을 감지하는 방법을 보여줍니다. #### HTML ```html <table id="outside"> - <tr><td id="t1">one</td></tr> - <tr><td id="t2">two</td></tr> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> </table> ``` #### JavaScript ```js -// Function to change the content of t2 +// t2의 콘텐츠를 바꾸는 함수 function modifyText() { - var t2 = document.getElementById("t2"); + const t2 = document.getElementById("t2"); if (t2.firstChild.nodeValue == "three") { t2.firstChild.nodeValue = "two"; } else { @@ -117,319 +160,338 @@ function modifyText() { } } -// add event listener to table -var el = document.getElementById("outside"); +// 표에 이벤트 수신기 추가 +const el = document.getElementById("outside"); el.addEventListener("click", modifyText, false); ``` -이 코드에서, `modifyText()` 는 `addEventListener()`를 사용하여 등록된 `click` 이벤트에 대한 리스너입니다. 테이블의 아무곳이나 클릭하더라도, 핸들러에서 버블링되고 `modifyText()` 가 실행됩니다. +위 코드의 `modifyText()`가 `addEventListener()`로 추가하는 `click` 이벤트의 수신기입니다. 표 요소의 어디를 클릭하든, 클릭 이벤트는 버를링을 통해 전파되다가 `modifyText()`를 발동하게 됩니다. + +#### 결과 + +{{EmbedLiveSample('간단한_수신기_추가하기')}} + +### 중단 가능한 수신기 추가하기 + +이 예제는 {{domxref("AbortSignal")}}로 중단할 수 있는 `addEventListener()`의 모습을 보입니다. + +#### HTML + +```html +<table id="outside"> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> +</table> +``` + +#### JavaScript + +```js +// 표에 중단 가능한 수신기 추가 +const controller = new AbortController(); +const el = document.getElementById("outside"); +el.addEventListener("click", modifyText, { signal: controller.signal } ); + +// t2의 콘텐츠를 바꾸는 함수 +function modifyText() { + const t2 = document.getElementById("t2"); + if (t2.firstChild.nodeValue == "three") { + t2.firstChild.nodeValue = "two"; + } else { + t2.firstChild.nodeValue = "three"; + controller.abort(); // 값이 "three"가 되면 수신기 제거 + } +} +``` + +이 예제는 앞선 첫 번째 예제를 수정해서, 표의 두 번째 행 내용이 "three"가 되면 `addEventListener()`의 옵션에 지정한 {{domxref("AbortSignal")}}의 `abort()`를 호출합니다. 그 결과로 클릭 이벤트 수신기가 해제되고, 두 번째 행의 내용은 "three"에서 바뀌지 않게 됩니다. #### 결과 -{{EmbedLiveSample('간단한_리스너_추가')}} +{{EmbedLiveSample('중단_가능한_수신기_추가하기')}} -### 익명 함수와 이벤트 리스너 +### 익명 함수와 이벤트 수신기 -여기서는 익명 함수를 사용하여 매개 변수를 이벤트 리스너에 전달하는 방법을 살펴보겠습니다. +여기선 익명 함수를 사용해 이벤트 수신기에 매개변수를 지정하는 방법을 보입니다. #### HTML ```html <table id="outside"> - <tr><td id="t1">one</td></tr> - <tr><td id="t2">two</td></tr> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> </table> ``` #### JavaScript ```js -// Function to change the content of t2 +// t2의 콘텐츠를 바꾸는 함수 function modifyText(new_text) { - var t2 = document.getElementById("t2"); + const t2 = document.getElementById("t2"); t2.firstChild.nodeValue = new_text; } -// Function to add event listener to table -var el = document.getElementById("outside"); +// 표에 이벤트 수신기 추가 +const el = document.getElementById("outside"); el.addEventListener("click", function(){modifyText("four")}, false); ``` -리스너는 코드를 캡슐화 하는 익명 함수입니다. 이 익명의 함수는 실제로 이벤트에 응답하는 책임이 있는 `modifyText()` 함수에 매개변수를 전달 할 수 있습니다. +`addEventListener()` 호출을 살펴보면, 실제로 이벤트에 반응할 `modifyText()` 함수에 매개변수를 제공하는 코드가 익명 함수에 의해 캡슐화된 모습을 볼 수 있습니다. -#### Result +#### 결과 -{{EmbedLiveSample('익명_함수와_이벤트_리스너')}} +{{EmbedLiveSample('익명_함수와_이벤트_수신기')}} -### 화살표 함수와 이벤트 리스너 +### 화살표 함수와 이벤트 수신기 -이 예제는 화살표 함수를 사용하여 구현된 간단한 이벤트 리스너를 보여줍니다. +이 예제는 화살표 함수를 사용해서 간단한 이벤트 수신기를 구현하는 모습을 보입니다. #### HTML ```html <table id="outside"> - <tr><td id="t1">one</td></tr> - <tr><td id="t2">two</td></tr> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> </table> ``` #### JavaScript ```js -// Function to change the content of t2 +// t2의 콘텐츠를 바꾸는 함수 function modifyText(new_text) { - var t2 = document.getElementById("t2"); + const t2 = document.getElementById("t2"); t2.firstChild.nodeValue = new_text; } -// Add event listener to table with an arrow function -var el = document.getElementById("outside"); +// 화살표 함수를 사용한 이벤트 수신기를 표에 추가 +const el = document.getElementById("outside"); el.addEventListener("click", () => { modifyText("four"); }, false); ``` #### 결과 -{{EmbedLiveSample('화살표_함수와_이벤트_리스너')}} +{{EmbedLiveSample('화살표_함수와_이벤트_수신기')}} -화살표 함수와 익명 함수는 유사하지만 서로 다른 `this`바인딩을 가집니다. 익명(모든 전통적인 자바스크립트 함수)는 그들 자신의 `this` 바인딩을 만들지만, 화살표 함수는 포함하고 있는 함수의 `this`바인딩을 상속합니다. +화살표 함수와 익명 함수는 비슷하지만, `this` 바인딩에 차이가 있다는 사실에 주의해야 합니다. 익명 함수(와 다른 모든 전통적인 JavaScript 함수)는 스스로의 `this` 바인딩을 생성하지만, 화살표 함수는 자신을 포함하고 있는 함수의 `this` 바인딩을 상속합니다. -즉, 화살표 함수를 사용할 때 포함하고 있는 함수에서 사용중인 변수 및 상수를 이벤트 핸들러에서 사용할 수 있습니다. +따라서 화살표 함수를 포함한 함수의 변수와 상수를 이벤트 처리 코드에서도 사용할 수 있습니다. -### 옵션의 사용 예제 +### 옵션 객체 사용하기 #### HTML ```html <div class="outer"> - outer, once & none-once - <div class="middle" target="_blank"> - middle, capture & none-capture - <a class="inner1" href="https://www.mozilla.org" target="_blank"> - inner1, passive & preventDefault(which is not allowed) - </a> - <a class="inner2" href="https://developer.mozilla.org/" target="_blank"> - inner2, none-passive & preventDefault(not open new page) - </a> - </div> + 바깥, 일회용 & 다회용 + <div class="middle" target="_blank"> + 중간, 캡처 & 비 캡처 + <a class="inner1" href="https://www.mozilla.org" target="_blank"> + 내부 1, 패시브 & (허용되지 않은) preventDefault + </a> + <a class="inner2" href="https://developer.mozilla.org/" target="_blank"> + 내부 2, 비 패시브 & preventDefault (새 페이지가 열리지 않음) + </a> + </div> </div> ``` #### CSS ```css - .outer, .middle, .inner1, .inner2 { - display:block; - width:520px; - padding:15px; - margin:15px; - text-decoration:none; - } - .outer{ - border:1px solid red; - color:red; - } - .middle{ - border:1px solid green; - color:green; - width:460px; - } - .inner1, .inner2{ - border:1px solid purple; - color:purple; - width:400px; - } +.outer, .middle, .inner1, .inner2 { + display: block; + width: 520px; + padding: 15px; + margin: 15px; + text-decoration: none; +} +.outer { + border: 1px solid red; + color: red; +} +.middle { + border: 1px solid green; + color: green; + width: 460px; +} +.inner1, .inner2 { + border: 1px solid purple; + color: purple; + width: 400px; +} ``` #### JavaScript ```js - let outer = document.getElementsByClassName('outer') [0]; - let middle = document.getElementsByClassName('middle')[0]; - let inner1 = document.getElementsByClassName('inner1')[0]; - let inner2 = document.getElementsByClassName('inner2')[0]; - - let capture = { - capture : true - }; - let noneCapture = { - capture : false - }; - let once = { - once : true - }; - let noneOnce = { - once : false - }; - let passive = { - passive : true - }; - let nonePassive = { - passive : false - }; - - - outer.addEventListener('click', onceHandler, once); - outer.addEventListener('click', noneOnceHandler, noneOnce); - middle.addEventListener('click', captureHandler, capture); - middle.addEventListener('click', noneCaptureHandler, noneCapture); - inner1.addEventListener('click', passiveHandler, passive); - inner2.addEventListener('click', nonePassiveHandler, nonePassive); - - function onceHandler(event) - { - alert('outer, once'); - } - function noneOnceHandler(event) - { - alert('outer, none-once, default'); - } - function captureHandler(event) - { - //event.stopImmediatePropagation(); - alert('middle, capture'); - } - function noneCaptureHandler(event) - { - alert('middle, none-capture, default'); - } - function passiveHandler(event) - { - // Unable to preventDefault inside passive event listener invocation. - event.preventDefault(); - alert('inner1, passive, open new page'); - } - function nonePassiveHandler(event) - { - event.preventDefault(); - //event.stopPropagation(); - alert('inner2, none-passive, default, not open new page'); - } -``` +const outer = document.querySelector('.outer'); +const middle = document.querySelector('.middle'); +const inner1 = document.querySelector('.inner1'); +const inner2 = document.querySelector('.inner2'); -#### Result - -옵션이 어떻게 작동하는지 보려면 각각 outer, middle, inner 컨테이너를 클릭해 보세요. - -{{ EmbedLiveSample('옵션의_사용_예제', 600, 310, '', 'Web/API/EventTarget/addEventListener') }} - -`options` 객체에서 특정 값을 사용하기 전에, 모든 브라우저의 모든 버전이 지원하는 것은 아니므로, 사용자의 브라우저가 해당 기능을 지원하는지 확인하는 것이 좋습니다. 자세한 내용은 {{anch("Safely detecting option support")}} 을 참조하세요. - -## Other notes - -### 왜 `addEventListener`를 사용하나요? +const capture = { + capture : true +}; +const noneCapture = { + capture : false +}; +const once = { + once : true +}; +const noneOnce = { + once : false +}; +const passive = { + passive : true +}; +const nonePassive = { + passive : false +}; -`addEventListener()` 는 W3C 에서 지정한 DOM에 이벤트 리스너를 등록하는 방법입니다. 장점은 다음과 같습니다: +outer.addEventListener('click', onceHandler, once); +outer.addEventListener('click', noneOnceHandler, noneOnce); +middle.addEventListener('click', captureHandler, capture); +middle.addEventListener('click', noneCaptureHandler, noneCapture); +inner1.addEventListener('click', passiveHandler, passive); +inner2.addEventListener('click', nonePassiveHandler, nonePassive); -- 이벤트에 대해 하나 이상의 핸들러를 추가할 수 있습니다. 이는 {{Glossary("AJAX")}} 라이브러리, 자바스크립트 모듈, 또는 다른 라이브러리/확장 기능과 잘 작동해야 하는 다른 종류의 코드에 특히 유용합니다. -- 리스너가 활성화 되면 (캡쳐링과 버블링) 단계의 세밀한 제어를 제공합니다. -- HTML 요소뿐만 아니라, 모든 DOM 요소에서 작동합니다. +function onceHandler(event) { + alert('바깥, 일회용'); +} +function noneOnceHandler(event) { + alert('바깥, 다회용, 기본 값'); +} +function captureHandler(event) { + //event.stopImmediatePropagation(); + alert('중간, 캡처'); +} +function noneCaptureHandler(event) { + alert('중간, 비 캡처, 기본 값'); +} +function passiveHandler(event) { + // 패시브 수신기 내에서는 preventDefault 사용 불가 + event.preventDefault(); + alert('내부 1, 패시브, 새 페이지 열림'); +} +function nonePassiveHandler(event) { + event.preventDefault(); + //event.stopPropagation(); + alert('내부 2, 비 패시브, 기본 값, 새 페이지 열림'); +} +``` -대안으로, [이벤트 리스너를 등록하는 오래된 방법](#Older_way_to_register_event_listeners)은 아래에 설명되어 있습니다. +#### 결과 -### 이벤트 전달중에 리스너 추가 +바깥과 중간, 내부 컨테이너를 반복해서 클릭해 각각의 옵션이 어떻게 동작하는지 확인해보세요. -{{domxref("EventListener")}} 가 이벤트 처리중에 {{domxref("EventTarget")}}에 추가되었다면, 그 이벤트는 리스너를 트리거하지 않습니다. 그러나 동일한 리스너는 버블링 단계와 같은 이벤트 흐름의 나중 단계에서 트리거 될 수 있습니다. +{{EmbedLiveSample('옵션_객체_사용하기', 600, 310)}} -### 다수의 동일한 이벤트 리스너 +`options` 객체에 특정 값을 지정하기 전에, 옵션의 지원 범위는 브라우저와 브라우저 버전에 따라 다르므로 브라우저가 해당 옵션을 지원하는지 먼저 확인하는 것이 좋습니다. [옵션 지원을 안전하게 감지하기](#옵션_지원을_안전하게_감지하기)에서 방법을 알아보세요. -만약 동일한 여러개의 `EventListener` 가 동일한 매개변수(parameter)로 동일한 `EventTarget` 에 등록되었다면, 중복된 항목(인스턴스)들은 버려집니다. `EventListener`는 두번 호출되지 않으며 {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} 메서드를 사용해 직접 제거할 필요가 없습니다. 그러나 익명 함수를 핸들러로 사용할 때, 루프를 도는 경우가 있습니다. 이 경우 단순히 반복적으로 호출하는 동일한 소스 코드를 사용하여 이벤트를 등록하더라도, 익명 함수는 동일하지 않고 이 때문에 리스너 또한 동일하지 않습니다. 이와 같은 경우 동일한 함수를 반복적으로 정의하는 것이 더 문제가 될 수 있습니다. (아래의 [메모리 문제](https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener$edit#Memory_issues)를 참조하세요.) +## 기타 일람 -### 핸들러 내부의 `this` 값 +### 이벤트 수신기 내부의 this 값 -유사한 요소 집합에 대한 일반적인 핸들러를 사용할 때와 같이, 이벤트 핸들러가 동작한 엘리먼트를 참조하는것이 좋습니다. +비슷한 요소 다수의 이벤트를 모두 처리할 수 있는 범용 수신기를 정의하는 경우, 부착된 요소의 참조를 가져와야 하는 상황이 종종 발생합니다. -`addEventListener()` 를 사용하여 핸들러 함수를 요소에 연결하면, 핸들러 내부의 [`this`](/en-US/docs/Web/JavaScript/Reference/Operators/this) 값은 요소에 대한 참조입니다. 이것은 핸들러에 전달 된 이벤트 인수(아규먼트)의 `currentTarget` 속성(프로퍼티)값과 같습니다. +`addEventListener()`를 사용해 요소에 수신기를 부착하게 되면 수신기 내부의 {{jsxref("Operators/this", "this")}} 값은 대상 요소를 가리키게 되며, 이는 수신기가 매개변수로 받게 되는 이벤트 객체의 `currentTarget` 속성과 같습니다. ```js my_element.addEventListener('click', function (e) { - console.log(this.className) // logs the className of my_element - console.log(e.currentTarget === this) // logs `true` + console.log(this.className) // my_element의 className 기록 + console.log(e.currentTarget === this) // `true` 기록 }) ``` -다시 말해, [화살표 함수에는 `this` 컨텍스트가 없습니다](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this). +다만 [화살표 함수는 스스로의 `this` 맥락을 가지지 않는다는 점](/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions)을 기억해야 합니다. ```js my_element.addEventListener('click', (e) => { - console.log(this.className) // WARNING: `this` is not `my_element` - console.log(e.currentTarget === this) // logs `false` + console.log(this.className) // 경고: `this`가 `my_element`가 아님 + console.log(e.currentTarget === this) // `false` 기록 }) ``` -HTML 소스의 요소(element)에 이벤트 핸들러(예: onclick)가 지정된 경우, 속성 값(attribute value)의 자바스크립트 코드는 효과적으로 `addEventListener()` 에 따라 `this`값을 바인드하는 핸들러 함수로 래핑됩니다. 코드 내에서 `this`가 발생하면 요소에 대한 참조를 나타냅니다. +HTML 소스 코드에서 ({{domxref("GlobalEventHandlers.onclick", "onclick")}} 특성 등을 사용해) 요소의 이벤트 수신기를 지정하는 경우, 이벤트 수신기 특성 내의 JavaScript 코드는 가상의 함수로 감싸인 후, 감싼 함수의 `this`를 `addEventListener()`와 같은 방식으로 바인딩하는 것으로 생각할 수 있습니다. 즉, 해당 특성의 값에서 등장하는 `this`는 특성이 속한 요소를 가리킵니다. ```html -<table id="my_table" onclick="console.log(this.id);"><!-- `this` refers to the table; logs 'my_table' --> +<table id="my_table" onclick="console.log(this.id);"><!-- `this`가 표를 가리키므로 'my_table'을 기록함 --> ... </table> ``` -속성 값(attribute value)의 코드에 의해 호출 된 함수 내부의 `this` 는 [표준 규칙들](/ko/docs/Web/JavaScript/Reference/Operators/this)에 따라 동작합니다. 다음은 그 예입니다. +참고로 이벤트 수신기 특성 안에서 호출한 함수의 `this`는 [표준 규칙](/ko/docs/Web/JavaScript/Reference/Operators/this)을 따라가며, 아래 코드로 확인할 수 있습니다. ```html <script> function logID() { console.log(this.id); } </script> -<table id="my_table" onclick="logID();"><!-- when called, `this` will refer to the global object --> +<table id="my_table" onclick="logID();"><!-- 호출 시, logID의 `this`는 전역 객체를 가리키게 됨 --> ... </table> ``` -`logID()` 내의 `this` 값은 {{domxref("Window")}} 전역 객체에 대한 참조입니다. (혹은 [strict mode](/en-US/docs/Web/JavaScript/Reference/Strict_mode) 의 경우 `undefined`입니다.) +`logID()` 내의 `this`는 전역 객체 {{domxref("Window")}}의 참조가 됩니다. (단, [엄격 모드](/ko/docs/Web/JavaScript/Reference/Strict_mode)에서는 `undefined`) -#### `bind()`를 사용하여 `this`지정하기 +#### bind()로 this 설정하기 -[`Function.prototype.bind()`](/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind) 메서드를 사용하면 지정한 함수에 대한 모든 호출에 대해 `this` 값으로 사용해야 하는 값을 지정할 수 있습니다. 이를 이용하여 함수가 호출 된 컨텍스트에 따라 `this` 가 무엇인지 명확하지 않은 문제를 쉽게 우회할 수 있습니다. 그러나 나중에 제거할 수 있도록, 주위에 리스너에 대한 참조를 유지해야 합니다. +{{jsxref("Function.prototype.bind()")}} 메서드를 사용하면 모든 후속 호출의 `this` 맥락을 고정할 수 있으므로, `this`의 값이 호출 위치에 따라 달라져서 정확히 파악하기 힘들 때 발생하는 문제를 먼저 방지할 수 있습니다. 다만, 바인드한 함수 참조를 어딘가에 보관해놔야 나중에 수신기를 제거할 수 있습니다. -다음은 `bind()` 를 사용한, 사용하지 않은 예제입니다 : +다음은 `bind()`를 사용하는 수신기와 사용하지 않는 수신기의 모습입니다. ```js -var Something = function(element) { - // |this| is a newly created object +const Something = function(element) { + // this는 Something 인스턴스 this.name = 'Something Good'; this.onclick1 = function(event) { - console.log(this.name); // undefined, as |this| is the element + console.log(this.name); // undefined, this는 element임 }; + this.onclick2 = function(event) { - console.log(this.name); // 'Something Good', as |this| is bound to newly created object + console.log(this.name); // 'Something Good', this는 Something 인스턴스 }; + + // bind가 onclick2의 this 맥락을 고정함 + this.onclick2 = this.onclick2.bind(this); + element.addEventListener('click', this.onclick1, false); - element.addEventListener('click', this.onclick2.bind(this), false); // Trick + element.addEventListener('click', this.onclick2, false); } -var s = new Something(document.body); +const s = new Something(document.body); ``` -또 다른 해결책은 `handleEvent()`라는 특수 함수를 사용하여 어떤 이벤트를 캐치 하는것입니다 : +다른 방법으로는 {{domxref("EventListener")}} 인터페이스의 `handleEvent()` 메서드를 구현해 모든 이벤트에 대응하는 것입니다. ```js -var Something = function(element) { - // |this| is a newly created object +const Something = function(element) { + // this는 Something 인스턴스 this.name = 'Something Good'; this.handleEvent = function(event) { - console.log(this.name); // 'Something Good', as this is bound to newly created object + console.log(this.name); // 'Something Good', this는 Something 인스턴스로 바인딩 됨 switch(event.type) { case 'click': - // some code here... + // 다른 코드... break; case 'dblclick': - // some code here... + // 다른 코드... break; } }; - // Note that the listeners in this case are |this|, not this.handleEvent + // 수신기 매개변수가 this.handleEvent가 아니라 this인 것에 주의 element.addEventListener('click', this, false); element.addEventListener('dblclick', this, false); - // You can properly remove the listeners + // 수신기 제거도 가능 element.removeEventListener('click', this, false); element.removeEventListener('dblclick', this, false); } -var s = new Something(document.body); +const s = new Something(document.body); ``` -*`this`에 대한 참조를 처리하는 또 다른 방법은,* `EventListener` 에 함수를 전달하는 것입니다. 이 함수는 접근을 필요로 하는 필드가 들어있는, 객체의 메서드를 호출하는 함수입니다: +`this` 참조를 처리할 수 있는 또 다른 방법으로는 객체의 필드에 접근해야 하는 메서드를 익명 함수로 감싸서 제공하는 것이 있습니다. ```js class SomeClass { @@ -439,229 +501,191 @@ class SomeClass { } register() { - var that = this; - window.addEventListener('keydown', function(e) {return that.someMethod(e);}); + const that = this; + window.addEventListener('keydown', function(e) { that.someMethod(e); }); } someMethod(e) { console.log(this.name); switch(e.keyCode) { case 5: - // some code here... + // 다른 코드... break; case 6: - // some code here... + // 다른 코드... break; } } } -var myObject = new SomeClass(); +const myObject = new SomeClass(); myObject.register(); ``` -### 오래된 인터넷 익스플로러와 attachEvent +### 이벤트 수신기 안팎으로 데이터 옮기기 + +이벤트 수신기에 데이터를 제공하는 것은 물론, 수신기 실행이 끝난 후 결과를 가져오는 것 또한 매우 어려워보일 것입니다. 이벤트 수신기는 유일한 매개변수로 [이벤트 객체](/ko/docs/Learn/JavaScript/Building_blocks/Events#이벤트_객체)만 받으며, 반환하는 모든 값은 무시됩니다. 그러면 어떻게 수신기에 데이터를 전달하거나, 그 밖으로 데이터를 가져올 수 있을까요? 몇 가지 좋은 방법을 소개합니다. -인터넷 익스플로러 9 이전 버전에서는, 표준 `addEventListener()` 가 아닌 {{domxref("EventTarget.attachEvent", "attachEvent()")}}를 사용해야 합니다. IE의 경우 위의 예제를 다음과 같이 수정합니다: +#### this로 이벤트 수신기에 데이터 전달하기 + +[위에서 언급했듯](#bind로_this_설정하기), `Function.prototype.bind()`를 사용하면 `this` 참조 변수를 통해 수신기에 값을 전달할 수 있습니다. ```js -if (el.addEventListener) { - el.addEventListener('click', modifyText, false); -} else if (el.attachEvent) { - el.attachEvent('onclick', modifyText); -} +const myButton = document.getElementById('my-button-id'); +const someString = 'Data'; + +myButton.addEventListener('click', function () { + console.log(this); // 예상 값: 'Data' +}.bind(someString)); ``` -`attachEvent()`의 단점은 다음과 같습니다: `this`의 값이 이벤트가 바인드되어 있는 요소 대신에, `window`객체에 대한 참조가 됩니다. +이 방법은 수신기가 발동된 대상을 알 필요가 없을 때 적합하며, 매개변수를 통해 값을 제공하는 것과 크게 다르지 않은 방법을 제공한다는 점이 장점입니다. -`attachEvent()` 메서드는 `onresize` 이벤트와 쌍을 이루어 웹 페이지의 특정 요소의 크기가 리사이징 되는 시점을 감지할 수 있습니다. `mselementresize` 라는 독점적인 이벤트는, 이벤트 핸들러를 등록하는 `addEventListener` 메서드와 함께 사용할 때 `onresize`와 유사한 기능을 제공하여, 특정 HTML 요소의 크기를 리사이징 할 때 실행됩니다. +#### 바깥 스코프 속성으로 이벤트 수신기에 데이터 전달하기 -### 호환성 +바깥 스코프에서 `const`, `let`을 사용해 변수를 선언할 경우, 해당 스코프 안의 모든 함수에서도 해당 변수에 접근할 수 있습니다([함수](/ko/docs/Glossary/Function#여러_함수_형식들) 문서에서 바깥/내부 함수에 대한 정보를, [`var`](/ko/docs/Web/JavaScript/Reference/Statements/var#암묵적인_전역변수와_외부_함수_범위) 문서에서 변수 스코프에 대한 정보를 읽어보세요). 따라서, 이벤트 수신기가 바깥 데이터에 접근할 수 있는 가장 쉬운 방법은, 그 데이터를 이벤트 수신기가 선언된 스코프에서 접근할 수 있도록 하는 것입니다. -스크립트 시작 부분에 다음 코드를 사용하여, 인터넷 익스플로러 8 에서 지원하지 않는 `addEventListener()`, `removeEventListener()`, {{domxref("Event.preventDefault()")}}, {{domxref("Event.stopPropagation()")}} 을 해결할 수 있습니다. 이 코드는 `handleEvent()`와 {{event("DOMContentLoaded")}} 이벤트에 대한 사용을 지원합니다. +```js +const myButton = document.getElementById('my-button-id'); +let someString = 'Data'; -<div class="note"><p><strong>참고: </strong>IE8 에서는 <code>useCapture</code>를 지원할 수 있는 다른 방법이 없습니다. 다음의 코드는 IE8 지원만 추가합니다. 이 IE8 폴리필은 표준 모드에서만 작동합니다: doctype 선언이 필요합니다.</p></div> +myButton.addEventListener('click', function() { + console.log(someString); // 예상 값: 'Data' -```js -(function() { - if (!Event.prototype.preventDefault) { - Event.prototype.preventDefault=function() { - this.returnValue=false; - }; - } - if (!Event.prototype.stopPropagation) { - Event.prototype.stopPropagation=function() { - this.cancelBubble=true; - }; - } - if (!Element.prototype.addEventListener) { - var eventListeners=[]; - - var addEventListener=function(type,listener /*, useCapture (will be ignored) */) { - var self=this; - var wrapper=function(e) { - e.target=e.srcElement; - e.currentTarget=self; - if (typeof listener.handleEvent != 'undefined') { - listener.handleEvent(e); - } else { - listener.call(self,e); - } - }; - if (type=="DOMContentLoaded") { - var wrapper2=function(e) { - if (document.readyState=="complete") { - wrapper(e); - } - }; - document.attachEvent("onreadystatechange",wrapper2); - eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper2}); - - if (document.readyState=="complete") { - var e=new Event(); - e.srcElement=window; - wrapper2(e); - } - } else { - this.attachEvent("on"+type,wrapper); - eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper}); - } - }; - var removeEventListener=function(type,listener /*, useCapture (will be ignored) */) { - var counter=0; - while (counter<eventListeners.length) { - var eventListener=eventListeners[counter]; - if (eventListener.object==this && eventListener.type==type && eventListener.listener==listener) { - if (type=="DOMContentLoaded") { - this.detachEvent("onreadystatechange",eventListener.wrapper); - } else { - this.detachEvent("on"+type,eventListener.wrapper); - } - eventListeners.splice(counter, 1); - break; - } - ++counter; - } - }; - Element.prototype.addEventListener=addEventListener; - Element.prototype.removeEventListener=removeEventListener; - if (HTMLDocument) { - HTMLDocument.prototype.addEventListener=addEventListener; - HTMLDocument.prototype.removeEventListener=removeEventListener; - } - if (Window) { - Window.prototype.addEventListener=addEventListener; - Window.prototype.removeEventListener=removeEventListener; - } - } -})(); + someString = 'Data Again'; +}); + +console.log(someString); // 예상 값: 'Data' ('Data Again'을 출력하지 않음) ``` -### 이벤트 리스너를 등록하는 고전적인 방법 +> **참고:** 내부 스코프에서 바깥 스코프의 `const`와 `let` 변수에 접근할 수는 있지만, 수신기 내에서 변수의 값을 바꾸더라도 바깥 스코프에 그 변경점이 나타날 것으로 생각해서는 안됩니다. 이벤트 수신기가 발동하는 시점에는 이미 수신기가 속한 스코프가 실행을 마쳤을 것이기 때문입니다. + +#### 객체를 사용해 이벤트 수신기 안팎으로 데이터 전달하기 + +자신을 참조하는 변수가 메모리에 남아있는 한, 객체는 메모리에서 사라지지 않습니다. 이 성질에 더해, 객체는 속성을 갖는다는 점, 그리고 참조로 전달된다는 점을 활용하면 스코프 안팎에서 데이터를 교환하는 창구로 객체를 이용할 수 있습니다. + +> **참고:** JavaScript에서는 함수도 사실 객체입니다. 따라서 함수도 속성을 가질 수 있고, 메모리에 유지되는 변수에 할당한 경우 실행 후에도 메모리에서 해제되지 않습니다. -`addEventListener()`는 DOM 2 [Events](http://www.w3.org/TR/DOM-Level-2-Events) 명세와 함께 도입되었습니다. 그 전에는 다음과 같이 이벤트 리스너를 등록했습니다: +객체를 참조하는 변수가 메모리에 존재하는 한 객체 속성을 사용해 메모리에 데이터를 저장할 수 있으니, 이벤트 수신기 내부로 데이터를 전달할 때도 사용할 수 있고, 이벤트 처리기 실행이 끝난 후 변화된 데이터를 가져와야 할 때도 사용할 수 있습니다. 아래 코드를 살펴보세요. ```js -// Passing a function reference ? do not add '()' after it, which would call the function! -el.onclick = modifyText; +const myButton = document.getElementById('my-button-id'); +const someObject = {aProperty: 'Data'}; -// Using a function expression -element.onclick = function() { - // ... function logic ... -}; +myButton.addEventListener('click', function() { + console.log(someObject.aProperty); // 예상 값: 'Data' + + someObject.aProperty = 'Data Again'; // 값 변경 +}); + +window.setInterval(function() { + if (someObject.aProperty === 'Data Again') { + console.log('Data Again: True'); + someObject.aProperty = 'Data'; // 다음 이벤트 실행을 기다리기 위해 값 초기화 + } +}, 5000); ``` -This 이 메서드는 요소의 기존 `click` 이벤트 리스너가 있을 경우에, 그것을 대체합니다. `blur` (`onblur`) 및 `keypress` (`onkeypress`) 와 같은 다른 이벤트 및 이벤트 핸들러도 비슷하게 작동합니다. +위 예제를 보면, 이벤트 수신기와 인터벌 함수가 정의된 스코프는 `someObject.aProperty`가 바뀌기 전에 실행이 끝나겠지만, `someObject`의 참조가 수신기와 인터벌 함수 메모리에 계속 남아있기 때문에, 양쪽 모두에서 같은 데이터에 접근할 수 있습니다. 즉, 한 쪽이 데이터를 바꾸면 반대편에서도 바뀐 데이터를 볼 수 있습니다. + +> **참고:** 객체는 변수에 참조, 실제 데이터가 저장된 메모리의 주소로 할당됩니다. 이 말은 곧, 객체를 담고 있는 변수를 사용하면, 같은 객체를 담은 다른 변수에도 영향을 줄 수 있다는 뜻입니다. 두 개의 변수가 같은 객체를 참조(e.g. `let a = b = {aProperty: 'Yeah'};`)하면, 한 쪽의 변수 데이터만 바꿔도 다른 쪽 데이터가 같이 바뀝니다. -이것은 본질적으로 {{glossary("DOM", "DOM 0")}}의 일부였기 때문에, 이벤트 리스너를 추가하는데 매우 광범위하게 지원되며 특별한 크로스 브라우징 코드가 필요하지 않습니다. 이것은 일반적으로 `addEventListener()`의 추가 기능이 필요하지 않으면, 이벤트 리스너를 동적으로 등록하는데 사용합니다. +> **참고:** 객체는 변수에 참조로 저장되기 때문에, 함수에서 객체를 반환하면 함수가 종료된 이후에도 계속 지속(데이터를 잃지 않도록 메모리에 유지)시킬 수 있습니다. -### 메모리 이슈 +### 메모리 문제 ```js -var i; -var els = document.getElementsByTagName('*'); +const els = document.getElementsByTagName('*'); -// Case 1 -for(i=0 ; i<els.length ; i++){ +// 상황 1 +for(let i=0 ; i < els.length; i++){ els[i].addEventListener("click", function(e){/*do something*/}, false); } -// Case 2 +// 상황 2 function processEvent(e){ - /*do something*/ + /* do something */ } -for(i=0 ; i<els.length ; i++){ +for(let i=0 ; i < els.length; i++){ els[i].addEventListener("click", processEvent, false); } ``` -위의 첫 번째 경우, 루프의 각 반복마다 새로운 익명 핸들러 함수가 생성됩니다. 두 번째 경우에는 이전에 선언한 동일한 함수를 이벤트 핸들러로 사용하므로, 메모리 소비가 줄어듭니다. 또한 첫 번째 경우에는 removeEventListener()를 호출할 수 없습니다. 익명 함수에 대한 참조가 유지되지 않기 때문입니다.(루프가 생성할 수 있는 여러개의 익명 함수 중 하나에 보관되지 않습니다) 두 번째 경우에는 `processEvent`가 함수 참조이기 때문에, `myElement.removeEventListener("click", processEvent, false)`를 수행할 수 있습니다. - -사실, 메모리 소비와 관련하여, 함수 참조를 유지하는 것은 진짜 문제가 아닙니다. 오히려 정적 함수 참조를 유지하는 것이 부족합니다. 아래의 두 경우(3,4번째 케이스) 모두 함수 참조가 유지되지만, 각 반복에서 재정의 되므로 정적이 아닙니다. 세 번째 경우에는 익명 함수에 대한 참조가, 반복될 때 마다 다시 할당됩니다. 네 번째 경우에는 전체 함수 정의가 변경되지 않지만, 새로운 것처럼(컴파일러에 의해 \[\[promoted]]되지 않는 한) 반복적으로 정의되고 있고 그래서 정적이지 않습니다. 따라서 간단하게 \[\[여러개의 동일한 이벤트 리스너]]인 것처럼 보이지만, 두 경우 모두 각 반복은 핸들러 함수에 대한 고유한 참조로 새로운 리스너를 생성합니다. 그러나 함수 정의 자체는 변경되지 않으므로, 모든 중복 리스너에 대해 같은 함수가 여전히 호출될 수 있습니다.(특히 코드가 최적화되는 경우) +위 코드에서 상황 1의 경우에는 반복문의 매 반복마다 새로운 익명 처리기 함수가 생성됩니다. 반면 상황 2에서는 사전에 정의한 함수를 이벤트 처리기로 사용하므로 처리기 함수를 하나만 사용하고, 따라서 더 작은 메모리 공간만 사용합니다. 더군다나 상황 1에서는, 익명 함수에 대한 참조를 유지하지 않으므로 {{domxref("EventTarget.removeEventListener", "removeEventListener()")}}를 호출할 수 없습니다. 반면 상황 2에서는, `processEvent`가 처리기 함수를 가리키므로 `myElement.removeEventListener("click", processEvent, false)`를 할 수 있습니다. -또한 두 경우 모두 함수 참조가 유지되었지만, 각 가산에 대해 반복적으로 재정의 되었습니다. 위에서 사용했던 remove 문(statement)으로는 리스너를 제거할 수 있지만, 마지막으로 추가한 리스너만 제거됩니다. +사실, 메모리 소비와 관련하여, 함수 참조를 유지하지 못하는 것은 중요한 문제가 아닙니다. 진짜 문제는 함수 참조를 '정적으로' 유지하지 못하는 것입니다. 이 점을 보여주는 아래의 상황 3과 상황 4에서는 함수 참조를 유지하긴 하지만, 매 반복마다 재정의됩니다. 상황 3에서는 반복할 때마다 익명 함수에 대한 참조를 재할당하고, 상황 4에서는 함수 전체 정의는 변하지 않지만 매번 마치 새로운 함수처럼 반복적으로 재정의되므로 두 상황 모두 정적이지 않습니다. 따라서 코드를 보기엔 다수의 동일한 이벤트 수신기처럼 보이지만, 사실 각 반복마다 새로운 처리기를 참조하는 새로운 이벤트 수신기를 생성하고 있는 것입니다. ```js -// For illustration only: Note "MISTAKE" of [j] for [i] thus causing desired events to all attach to SAME element +const els = document.getElementsByTagName('*'); -// Case 3 -for(var i=0, j=0 ; i<els.length ; i++){ - /*do lots of stuff with j*/ - els[j].addEventListener("click", processEvent = function(e){/*do something*/}, false); +function processEvent(e){ + /* do something */ +} + +// 시연을 위해 [i] 대신 [j]를 사용하는 실수를 한 것에 주의하세요. 반복문 내에서 정의한 수신기를 모두 첫 요소에 등록하고 있습니다. + +// 상황 3 +for(let i = 0, j = 0 ; i < els.length ; i++){ + els[j].addEventListener("click", processEvent = function(e){/* do something */}, false); } -// Case 4 -for(var i=0, j=0 ; i<els.length ; i++){ - /*do lots of stuff with j*/ - function processEvent(e){/*do something*/}; +// 상황 4 +for(let i = 0, j = 0 ; i < els.length ; i++){ + function processEvent(e){/* do something */}; els[j].addEventListener("click", processEvent, false); } ``` -### passive 리스너로 스크롤링 성능 향상 +또한 상황 3과 4에서는 함수 참조가 유지되긴 하지만 매번 `addEventListener()` 전에 재정의되므로, `removeEventListener("click", processEvent, false)`로 수신기를 제거할 수는 있으나 오직 마지막으로 정의된 수신기만 제거됩니다. + +### 패시브 수신기로 스크롤 성능 향상 -명세에 따르면, `passive` option의 기본값은 항상 `false` 입니다. 그러나 이것은 이벤트 리스너가 특정 터치 이벤트를 처리하는 경우(다른 이벤트를 포함하여), 스크롤을 처리하는 동안 브라우저의 메인 스레드를 차단하기 때문에, 스크롤 처리 시 성능이 크게 저하될 수 있습니다. +명세에 따르면, `passive` 옵션의 기본 값은 항상 `false` 입니다. 그러나 이 기본 값으로 인해 터치 이벤트 등 일부 이벤트의 수신기가 스크롤을 처리 중인 브라우저 메인 스레드를 블록할 가능성이 생기고, 따라서 스크롤 성능이 크게 저하될 수 있습니다. -이러한 문제를 방지하기 위하여, 일부 브라우저(특히 크롬과 파이어폭스)는 document-level nodes인 {{domxref("Window")}}, {{domxref("Document")}}, {{domxref("Document.body")}}의 경우 {{event("touchstart")}} 와{{event("touchmove")}} 이벤트에 대해 `passive` 옵션의 기본값을 `true`로 변경했습니다. 이렇게 하면 이벤트 리스너가 호출되지 않으므로, 사용자가 스크롤 하는 동안 페이지 렌더링을 차단할 수 없습니다. +이 문제를 방지하기 위해 일부 브라우저(Chrome과 Firefox 등)는 문서 레벨 노드인 {{domxref("Window")}}, {{domxref("Document")}}, {{domxref("Document.body")}}의 {{event("touchstart")}}와 {{event("touchmove")}} 이벤트에 대해선 `passive`의 기본 값을 `true`로 바꿔 적용합니다. 패시브 이벤트 수신기는 이벤트를 [취소](/ko/docs/Web/API/Event/preventDefault)할 수 없으므로 사용자가 스크롤할 때 브라우저의 렌더링을 방해하지 않습니다. -> **참고:** 이 변경된 동작을 구현하는 브라우저(혹은 브라우저의 버전)을 알아야 할 경우 아래의 호환성 표를 참조하세요. +> **참고:** 어떤 브라우저/버전에서 이렇게 동작하는지는 아래의 브라우저 호환성 표에 나와있습니다. -다음과 같이 `passive`의 값을 명시적으로 `false`로 설정을 오버라이드 하여 이 동작을 무시할 수 있습니다: +`passive` 옵션에 명시적으로 `false`를 지정해서 이 동작을 막을 수 있습니다. ```js -/* Feature detection */ -var passiveIfSupported = false; +/* 기능 감지 */ +let passiveIfSupported = false; try { - window.addEventListener("test", null, Object.defineProperty({}, "passive", { get: function() { passiveIfSupported = { passive: true }; } })); + window.addEventListener("test", null, + Object.defineProperty( + {}, + "passive", + { + get: function() { passiveIfSupported = { passive: true }; } + } + ) + ); } catch(err) {} window.addEventListener('scroll', function(event) { - /* do something */ - // can't use event.preventDefault(); + /* do something */ + // event.preventDefault() 사용 불가 }, passiveIfSupported ); ``` -`addEventListener()`에 대한 `options` 매개변수를 지원하지 않는 이전 브라우저에서는, [feature detection](#Safely_detecting_option_support)를 사용하지 않고는 `useCapture` 인수를 사용하지 못하도록 해야 합니다. +`addEventListener()`가 `options` 매개변수를 지원하지 않는 구형 브라우저에서 `options` 객체를 지정하면 `useCapture` 매개변수를 사용할 수 없으므로, 위와 같이 [기능 감지](#옵션_지원을_안전하게_감지하기)를 거쳐야 합니다. -{{event("scroll")}} 이벤트의 기본 `passive` 값에 대해 걱정할 필요는 없습니다. 취소할 수 없기 때문에, 이벤트 리스너는 페이지 렌더링을 차단할 수 없습니다. +{{event("scroll")}} 이벤트에 대해서는 `passive` 옵션을 고려하지 않아도 됩니다. 어차피 취소할 수 없는 이벤트라서, 수신기가 페이지 렌더링을 막을 수도 없기 때문입니다. ## 명세 -| Specification | Status | Comment | -| ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------ | -| {{SpecName("DOM WHATWG", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}} | {{Spec2("DOM WHATWG")}} | | -| {{SpecName("DOM4", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}} | {{Spec2("DOM4")}} | | -| {{SpecName("DOM2 Events", "#Events-EventTarget-addEventListener", "EventTarget.addEventListener()")}} | {{Spec2("DOM2 Events")}} | Initial definition | +{{Specifications}} ## 브라우저 호환성 -{{Compat("api.EventTarget.addEventListener", 3)}} +{{Compat}} ## 같이 보기 - {{domxref("EventTarget.removeEventListener()")}} -- [Creating and triggering custom events](/en-US/docs/DOM/Creating_and_triggering_events) -- [More details on the use of `this` in event handlers](http://www.quirksmode.org/js/this.html) +- [이벤트 생성 및 발동](/ko/docs/DOM/Creating_and_triggering_events) +- [이벤트 처리기의 `this`에 관한 더 자세한 정보](https://www.quirksmode.org/js/this.html) diff --git a/files/ko/web/api/eventtarget/dispatchevent/index.md b/files/ko/web/api/eventtarget/dispatchevent/index.md index a3a8ffb3ef..5883012c61 100644 --- a/files/ko/web/api/eventtarget/dispatchevent/index.md +++ b/files/ko/web/api/eventtarget/dispatchevent/index.md @@ -2,54 +2,55 @@ title: EventTarget.dispatchEvent() slug: Web/API/EventTarget/dispatchEvent tags: - - API - - DOM - - DOM 엘리먼트 메소드 - - Gecko - - 메소드 + - Method + - Reference +browser-compat: api.EventTarget.dispatchEvent translation_of: Web/API/EventTarget/dispatchEvent --- -{{APIRef("DOM Events")}} +{{APIRef("DOM")}} -영향을 받는 {{domxref("EventListener")}} 를 적절한 순서로 호출하는 지정된 {{domxref("EventTarget")}} 에서 {{domxref("Event")}} 를 (동기적으로) 디스패치합니다. 일반 이벤트 처리 규칙(capturing 과 선택적인 bubbling 단계를 포함해)은 `dispatchEvent()` 를 사용하여 수동으로 전달 된 이벤트에도 적용됩니다. +{{domxref("EventTarget")}} 인터페이스의 **`dispatchEvent()`** 메서드는 `EventTarget` 객체로 {{domxref("Event")}}를 발송해서, 해당 이벤트에 대해 등록된 {{domxref("EventListener")}}들을 (동기적으로) 순서대로 호출합니다. `dispatchEvent()`를 통해 직접 발송한 이벤트에도 캡처링과 버블링 단계를 포함한 일반적인 이벤트 처리 규칙이 적용됩니다. -<h2 id="Syntax" name="Syntax">구문</h2> +`dispatchEvent()` 호출은 이벤트 발송 과정의 마지막 단계입니다. 발송에 앞서 우선 {{domxref("Event/Event", "Event()")}} 생성자로 이벤트를 생성 및 초기화해야 합니다. - cancelled = !target.dispatchEvent(event) +> **참고:** `dispatchEvent()` 사용 시, {{domxref("Event.target")}} 속성은 현재 `EventTarget`으로 초기화됩니다. -### 파라미터 +브라우저가 발송하는 "네이티브" 이벤트는 [이벤트 루프](/ko/docs/Web/JavaScript/EventLoop)를 통해 비동기적으로 처리기들을 호출하지만, `dispatchEvent()`로 발송된 이벤트는 처리기를 동기적으로 호출합니다. 즉, 모든 적합한 처리기의 호출과 반환이 끝나야 `dispatchEvent()` 역시 반환합니다. -- `event` 는 디스패치될 {{domxref("Event")}} 객체입니다. -- `target` 은 {{domxref("Event", "", "target")}} 를 초기화하기 위해서 사용되고 어떤 이벤트 리스너를 호출할 것인지 결정합니다. +## 구문 -### 반환 값 - -- 적어도 하나의 이벤트 핸들러가 그 이벤트를 처리하면서 {{domxref("Event.preventDefault()")}} 를 호출하였다면 `false` 를 반환하고 그렇지 않으면 `true` 를 반환합니다. +```js +dispatchEvent(event) +``` -`dispatchEvent` 메서드는 그 이벤트의 타입이 메서드의 호출이전에 초기화되지 않았을 경우 `UNSPECIFIED_EVENT_TYPE_ERR` 에러를 발생시킵니다. 또는 이벤트의 타입이 `null` 이거나 공백 스트링을 경우에도 같은 에러를 발생시킵니다. 이벤트 핸들러에 의해 발생한 이벤트는 잡히지 않은 예외(uncaugt exceptions)로 보고가 되며 이벤트 핸들러는 내부 콜스택(nested callstack)에서 실행이 됩니다. 이는 곧 완료가 될 때까지 호출자(caller)를 막는 다는 뜻이고 예외들이 호출자(caller)에게 전파(propagate)되지 않음을 말합니다. +### 매개변수 -<h2 id="Notes" name="Notes">노트</h2> +- `event` + - : 발송할 {{domxref("Event")}} 객체입니다. {{domxref("Event.target")}}은 현재 {{domxref("EventTarget")}}으로 설정됩니다. -DOM에 의해 시작되고 [이벤트 루프](https://developer.mozilla.org/ko/docs/Web/JavaScript/EventLoop)를 통해 이벤트 핸들러를 비동기 적으로 호출하는 "네이티브" 이벤트와 달리 `dispatchEvent` 는 이벤트 핸들러를 동기적으로 호출합니다. `dispatchEvent` 를 호출 한 후 코드가 계속되기 전에 모든 해당 이벤트 핸들러가 실행되고 리턴됩니다. +### 반환 값 -implementation's 이벤트 모델의 디스패치 이벤트에 사용되는 create-init-dispatch 프로세스의 마지막 단계입니다. 이벤트는 [Event 생성자](https://developer.mozilla.org/ko/docs/Web/API/Event/Event)를 사용하여 만들 수 있습니다. +`event`가 취소 가능하고, 이벤트 처리기 중 하나에서 {{domxref("Event.preventDefault()")}}를 호출한 경우 `false`, 그 외에는 `true`. -[Event 객체 레퍼런스](https://developer.mozilla.org/ko/docs/Web/API/Event "DOM/event")도 한번 확인해 보세요 +### 예외 -<h2 id="Example" name="Example">예시</h2> +- `InvalidStateError` {{domxref("DomException")}} + - : 이벤트 초기화 시 이벤트 유형을 지정하지 않은 경우 발생합니다. -[이벤트 생성 및 트리거](https://developer.mozilla.org/ko/docs/Web/Guide/Events/Creating_and_triggering_events "/en-US/docs/Web/Guide/DOM/Events/Creating_and_triggering_events") 문서를 확인하세요. +> **경고:** 이벤트 처리기에서 발생한 예외는 처리하지 않은 예외로 보고됩니다. 이벤트 처리기는 중첩 호출 스택에서 동작하므로, 실행이 끝날 때까지 호출자는 대기하지만, 예외는 호출자로 전파되지 않습니다. -<h2 id="Specification" name="Specification">명세</h2> +## 예외 -| 명세 | 상태 | 코멘트 | -| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------- | ------------------------------ | -| {{SpecName('DOM WHATWG', '#dom-eventtarget-dispatchevent', 'EventTarget.dispatchEvent()')}} | {{ Spec2('DOM WHATWG') }} | DOM 2 Events 명세의 초기 정의. | +[이벤트 생성과 발동](/ko/docs/Web/Events/Creating_and_triggering_events)를 확인하세요. -<h2 id="Browser_Compatibility" name="Browser_Compatibility">브라우저 호환성</h2> +## 명세 +{{Specifications}} +## 브라우저 호환성 +{{Compat}} +## See also -{{Compat("api.EventTarget.dispatchEvent")}} +- The [Event object reference](/en-US/docs/Web/API/Event) diff --git a/files/ko/web/api/eventtarget/eventtarget/index.md b/files/ko/web/api/eventtarget/eventtarget/index.md index f10bf70dcf..2822690e75 100644 --- a/files/ko/web/api/eventtarget/eventtarget/index.md +++ b/files/ko/web/api/eventtarget/eventtarget/index.md @@ -1,29 +1,38 @@ --- title: EventTarget() slug: Web/API/EventTarget/EventTarget +tags: + - Constructor + - Reference +browser-compat: api.EventTarget.EventTarget translation_of: Web/API/EventTarget/EventTarget --- -{{APIRef("DOM Events")}} +{{APIRef("DOM")}} -**`EventTarget()`** 생성자는 새로운 {{domxref("EventTarget")}} 객체 인스턴스를 만듭니다. +**`EventTarget()`** 생성자는 새로운 {{domxref("EventTarget")}} 객체 인스턴스를 생성합니다. -## Syntax +> **참고:** 이 생성자를 명시적으로 사용하는 경우는 거의 없습니다. 보통은 {{domxref("EventTarget")}}을 상속하는 객체의 생성자 내에서 [`super`](/ko/docs/Web/JavaScript/Reference/Operators/super) 키워드로 사용됩니다. - var myEventTarget = new EventTarget(); +## 구문 -### Parameters +```js +new EventTarget(); +``` -None. +### 매개변수 -### Return value +없음. -{{domxref("EventTarget")}} 객체의 인스턴스를 반환합니다. +### 반환 값 -## Examples +{{domxref("EventTarget")}} 객체의 새로운 인스턴스. -<pre class="brush: js" id="ct-20">class MyEventTarget extends EventTarget { +## 예제 + +```js +class MyEventTarget extends EventTarget { constructor(mySecret) { - super(); + super(); this._secret = mySecret; } @@ -38,17 +47,16 @@ myEventTarget.addEventListener("foo", function(e) { let event = new CustomEvent("foo", { detail: 7 }); myEventTarget.dispatchEvent(event); -let newValue = myEventTarget.secret; // == 7</pre> +let newValue = myEventTarget.secret; // == 7 +``` -## Specifications +## 명세 -| Specification | Status | Comment | -| -------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------- | -| {{SpecName('DOM WHATWG', '#dom-eventtarget-eventtarget', 'EventTarget() constructor')}} | {{Spec2('DOM WHATWG')}} | | +{{Specifications}} -## Browser compatibility +## 브라우저 호환성 -{{Compat("api.EventTarget.EventTarget")}} +{{Compat}} ## See also diff --git a/files/ko/web/api/eventtarget/index.md b/files/ko/web/api/eventtarget/index.md index a291659bec..d5c377b8a1 100644 --- a/files/ko/web/api/eventtarget/index.md +++ b/files/ko/web/api/eventtarget/index.md @@ -2,17 +2,14 @@ title: EventTarget slug: Web/API/EventTarget tags: - - API - - DOM - - DOM Events - - EventTarget - Interface - Reference +browser-compat: api.EventTarget translation_of: Web/API/EventTarget --- -{{ApiRef("DOM Events")}} +{{APIRef("DOM")}} -**`EventTarget`** 인터페이스는 이벤트를 받을 수 있으며, 이벤트에 대한 수신기(listener)를 가질 수 있는 객체가 구현하는 인터페이스입니다. 즉, 이벤트의 대상이 될 수 있는 객체는 `EventTarget`의 세 메서드를 구현합니다. +**`EventTarget`** 인터페이스는 이벤트를 수신할 수 있고, 수신한 이벤트에 대한 수신기(listener)를 가질 수 있는 객체가 구현하는 인터페이스입니다. 즉, 이벤트의 대상이 될 수 있는 객체는 `EventTarget`의 세 메서드를 구현합니다. {{domxref("Element")}}, {{domxref("Document")}}, {{domxref("Window")}}가 가장 흔한 이벤트 대상이며, 이외에도 {{domxref("XMLHttpRequest")}}, {{domxref("AudioNode")}}, {{domxref("AudioContext")}} 등의 객체도 이벤트 대상입니다. diff --git a/files/ko/web/api/eventtarget/removeeventlistener/index.md b/files/ko/web/api/eventtarget/removeeventlistener/index.md index 30f62d6e32..22d45a705f 100644 --- a/files/ko/web/api/eventtarget/removeeventlistener/index.md +++ b/files/ko/web/api/eventtarget/removeeventlistener/index.md @@ -1,181 +1,137 @@ --- title: EventTarget.removeEventListener() slug: Web/API/EventTarget/removeEventListener +tags: + - Method + - Reference +browser-compat: api.EventTarget.removeEventListener translation_of: Web/API/EventTarget/removeEventListener --- -{{APIRef("DOM Events")}} +{{APIRef("DOM")}} -**`EventTarget.removeEventListener()`** 메서드는 이전에{{domxref("EventTarget.addEventListener()")}}로 {{domxref("EventTarget")}} 에 등록했던 이벤트 리스너를 제거합니다. 이 이벤트 리스너는 이벤트 종류와 이벤트 리스너 함수 자체의 조합으로 식별되어 제거되며, 등록시 제공했던 다양한 옵션과 일치하는 이벤트 리스너만 제거할 수 있습니다. <span style="font-size: 1rem; letter-spacing: -0.00278rem;"> {{anch("Matching event listeners for removal")}}를 참고하세요.</span> +{{domxref("EventTarget")}} 인터페이스의 **`EventTarget.removeEventListener()`** 메서드는 {{domxref("EventTarget.addEventListener()")}}로 이벤트 대상에 등록한 수신기를 제거합니다. 제거 대상 수신기의 식별은 이벤트 유형, 수신기 함수 참조, 그리고 식별에 관련된 다양한 옵션을 사용해 이뤄집니다. [제거할 이벤트 수신기의 식별](#제거할_이벤트_수신기의_식별)을 참고하세요. -## Syntax +`EventTarget`에 등록된 {{domxref("EventListener")}} 중 무엇에도 일치하지 않는 매개변수를 사용해서 `removeEventListener()`를 호출하면 아무 효과도 발생하지 않습니다. - target.removeEventListener(type, listener[, options]); - target.removeEventListener(type, listener[, useCapture]); +{{domxref("EventTarget")}}의 어느 수신기 중 하나가 이벤트를 처리하는 중에 다른 수신기를 제거할 경우, 제거된 {{domxref("EventListener")}}는 현재 이벤트에 대해 발동하지 않습니다. 그러나 다시 부착할 수는 있습니다. -### Parameters +> **경고:** 같은 수신기를 다른 캡처 플래그 값으로 두 번, 즉 한 번은 `capture` 플래그를 지정하고 한 번은 지정하지 않은 채 부착하는 경우 각각 따로따로 제거해야 합니다. 캡처 플래그를 지정한 수신기의 제거는 비 캡처 수신기에 영향을 주지 않고, 그 반대도 마찬가지입니다. -<dl><dt><code>type</code></dt><dd>제거할 이벤트 리스너의 이벤트 타입을 지정합니다.</dd><dt><code>listener</code></dt><dd>이벤트 타깃에서 제거할 이벤트 핸들러 함수, {{domxref("EventListener")}}를 지정합니다.</dd><dt><code>options</code> {{optional_inline}}</dt><dd>이벤트 리스너에 대한 특징, 즉 제거할 이벤트 리스너의 옵션들을 지정합니다. 지정할 수 있는 옵션들은 아래와 같습니다.<ul><li><code>capture</code>: 이 이벤트 타입의 이벤트들이 DOM 트리 내 모든 어떤 <code>EventTarget</code> 에 디스패치되기 전에 등록된 <code>listener</code> 들을 먼저 처리하도록 만들지 말지를 결정하는 {{jsxref("Boolean")}} 값.</li><li>{{non-standard_inline}}<code> mozSystemGroup</code>: Available only in code running in XBL or in Firefox' chrome, it is a {{jsxref("Boolean")}} defining if the listener is added to the system group. (비표준)</li></ul></dd><dt><code>useCapture</code> {{optional_inline}}</dt><dd>Specifies whether the {{domxref("EventListener")}} to be removed is registered as a capturing listener or not. If this parameter is absent, a default value of <code>false</code> is assumed.</dd><dd>If a listener is registered twice, one with capture and one without, remove each one separately. Removal of a capturing listener does not affect a non-capturing version of the same listener, and vice versa.</dd></dl> +{{domxref("EventTarget.addEventListener", "addEventListener()")}}에 {{domxref("AbortSignal")}}을 지정한 후, 나중에 {{domxref("AbortSignal.abort", "abort()")}}를 호출해서 수신기를 제거하는 방법도 있습니다. -### Return value +## 구문 -`undefined`. +```js +removeEventListener(type, listener); +removeEventListener(type, listener, options); +removeEventListener(type, listener, useCapture); +``` + +### 매개변수 + +- `type` + - : 이벤트 수신기를 제거할 이벤트 유형입니다. +- `listener` + - : 이벤트 대상에서 제거할 수신기 {{domxref("EventListener")}} 함수입니다. +- `options` {{optional_inline}} + - : 제거할 이벤트 수신기의 특징을 나타내는 옵션 객체입니다. + + 가능한 옵션은 다음과 같습니다. + + - `capture`: 제거할 {{domxref("EventListener")}}가 캡처링 수신기로 등록됐는지에 대한 여부를 나타내는 불리언 값입니다. 기본 값은 `false`입니다. + +- `useCapture` {{optional_inline}} + - : 제거할 {{domxref("EventListener")}}가 캡처링 수신기로 등록됐는지에 대한 여부를 나타내는 불리언 값입니다. 기본 값은 `false`입니다. + +### 반환 값. -### Matching event listeners for removal +없음. -Given an event listener previously added by calling {{domxref("EventTarget.addEventListener", "addEventListener()")}}, you may eventually come to a point at which you need to remove it. Obviously, you need to specify the same `type` and `listener` parameters to `removeEventListener()`, but what about the `options` or `useCapture` parameters? +### 제거할 이벤트 수신기의 식별 -While `addEventListener()` will let you add the same listener more than once for the same type if the options are different, the only option `removeEventListener()` checks is the `capture`/`useCapture` flag. Its value must match for `removeEventListener()` to match, but the other values don't. +{{domxref("EventTarget.addEventListener", "addEventListener()")}}로 이벤트 수신기를 추가했다면, 수신기를 제거해야 할 때가 오기도 합니다. 당연히 추가할 때 지정한 것과 같은 `type` 및 `listener`를 `removeEventListener()`의 매개변수로 지정해야 하겠지만, `options`나 `useCapture` 매개변수는 어떻게 해야 할까요? -For example, consider this call to `addEventListener()`: +`addEventListener()`는 옵션이 다르다면 이벤트 유형 하나에 같은 수신기를 여러 번 부착합니다. 그러나 `removeEventListener()`가 고려하는 옵션은 `capture`/`useCapture` 플래그 단 하나입니다. 따라서 `capture`/`useCapture` 값은 일치해야 하지만, 나머지 옵션은 일치하지 않아도 됩니다. + +다음의 `addEventListener()` 호출을 예시로 보겠습니다. ```js element.addEventListener("mousedown", handleMouseDown, true); ``` -Now consider each of these two calls to `removeEventListener()`: +이제 아래의 두 `removeEventListener()` 호출을 살펴보세요. ```js -element.removeEventListener("mousedown", handleMouseDown, false); // Fails -element.removeEventListener("mousedown", handleMouseDown, true); // Succeeds +element.removeEventListener("mousedown", handleMouseDown, false); // 실패 +element.removeEventListener("mousedown", handleMouseDown, true); // 성공 ``` -The first call fails because the value of `useCapture` doesn't match. The second succeeds, since `useCapture` matches up. +첫 번째 호출은 `useCapture`가 일치하지 않았기 때문에 실패하고, 두 번째 호출은 일치하기 때문에 성공합니다. -Now consider this: +이제 다음 코드를 확인하세요. ```js element.addEventListener("mousedown", handleMouseDown, { passive: true }); ``` -Here, we specify an `options` object in which `passive` is set to `true`, while the other options are left to the default value of `false`. +위 코드에서는 `passive`를 `true`로 지정한 `option` 객체를 지정했습니다. 다른 옵션은 기본 값인 `false`가 됩니다. + +아래의 `removeEventListener()` 호출 각각을 살펴보세요. `capture`나 `useCapture`가 `true`인 호출은 실패하고, 나머지는 모두 성공합니다. -Now look at each of these calls to `removeEventListener()` in turn. Any of them in which `capture` or `useCapture` is `true` fail; all others succeed. Only the `capture` setting matters to `removeEventListener()`. +`removeEventListener()`에 영향을 주는 옵션은 `capture` 뿐입니다. ```js -element.removeEventListener("mousedown", handleMouseDown, { passive: true }); // Succeeds -element.removeEventListener("mousedown", handleMouseDown, { capture: false }); // Succeeds -element.removeEventListener("mousedown", handleMouseDown, { capture: true }); // Fails -element.removeEventListener("mousedown", handleMouseDown, { passive: false }); // Succeeds -element.removeEventListener("mousedown", handleMouseDown, false); // Succeeds -element.removeEventListener("mousedown", handleMouseDown, true); // Fails +element.removeEventListener("mousedown", handleMouseDown, { passive: true }); // 성공 +element.removeEventListener("mousedown", handleMouseDown, { capture: false }); // 성공 +element.removeEventListener("mousedown", handleMouseDown, { capture: true }); // 실패 +element.removeEventListener("mousedown", handleMouseDown, { passive: false }); // 성공 +element.removeEventListener("mousedown", handleMouseDown, false); // 성공 +element.removeEventListener("mousedown", handleMouseDown, true); // 실패 ``` -It's worth noting that some browser releases have been inconsistent on this, and unless you have specific reasons otherwise, it's probably wise to use the same values used for the call to `addEventListener()` when calling `removeEventListener()`. - -## Notes - -If an {{domxref("EventListener")}} is removed from an {{domxref("EventTarget")}} while it is processing an event, it will not be triggered by the current actions. An {{domxref("EventListener")}} will not be invoked for the event it was registered for after being removed. However, it can be reattached. +다만 일부 브라우저 버전에서는 이 동작이 일관적이지 않으므로, 어쩔 수 없는 경우가 아니라면 `addEventListener()`에 지정한 옵션을 그대로 `removeEventListener()`에 제공하는 편이 낫습니다. -Calling `removeEventListener()` with arguments that do not identify any currently registered {{domxref("EventListener")}} on the `EventTarget` has no effect. +## 예제 -## Example - -This example shows how to add a `click`-based event listener and remove a `mouseover`-based event listener. +이 예제는 `click` 이벤트 수신기를 제거하는 `mouseover` 이벤트 수신기를 보입니다. ```js -var body = document.querySelector('body'), - clickTarget = document.getElementById('click-target'), - mouseOverTarget = document.getElementById('mouse-over-target'), - toggle = false; +const body = document.querySelector('body') +const clickTarget = document.getElementById('click-target') +const mouseOverTarget = document.getElementById('mouse-over-target') +let toggle = false; function makeBackgroundYellow() { - 'use strict'; - - if (toggle) { - body.style.backgroundColor = 'white'; - } else { - body.style.backgroundColor = 'yellow'; - } + if (toggle) { + body.style.backgroundColor = 'white'; + } else { + body.style.backgroundColor = 'yellow'; + } - toggle = !toggle; + toggle = !toggle; } clickTarget.addEventListener('click', - makeBackgroundYellow, - false + makeBackgroundYellow, + false ); mouseOverTarget.addEventListener('mouseover', function () { - 'use strict'; - - clickTarget.removeEventListener('click', - makeBackgroundYellow, - false - ); + clickTarget.removeEventListener('click', + makeBackgroundYellow, + false + ); }); ``` -## Specifications - -| Specification | Status | Comment | -| ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- | ------------------ | -| {{SpecName("DOM WHATWG", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}} | {{Spec2("DOM WHATWG")}} | | -| {{SpecName("DOM4", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}} | {{Spec2("DOM4")}} | | -| {{SpecName("DOM2 Events", "#Events-EventTarget-removeEventListener", "EventTarget.removeEventListener()")}} | {{Spec2("DOM2 Events")}} | Initial definition | - -## Browser compatibility +## 명세 +{{Specifications}} +## 브라우저 호환성 -{{Compat("api.EventTarget.removeEventListener", 3)}} - -## Polyfill to support older browsers - -`addEventListener()` and `removeEventListener()` are not present in older browsers. You can work around this by inserting the following code at the beginning of your scripts, allowing the use of `addEventListener()` and `removeEventListener()` in implementations that do not natively support it. However, this method will not work on Internet Explorer 7 or earlier, since extending the Element.prototype was not supported until Internet Explorer 8. - -```js -if (!Element.prototype.addEventListener) { - var oListeners = {}; - function runListeners(oEvent) { - if (!oEvent) { oEvent = window.event; } - for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) { - if (oEvtListeners.aEls[iElId] === this) { - for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); } - break; - } - } - } - Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) { - if (oListeners.hasOwnProperty(sEventType)) { - var oEvtListeners = oListeners[sEventType]; - for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) { - if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; } - } - if (nElIdx === -1) { - oEvtListeners.aEls.push(this); - oEvtListeners.aEvts.push([fListener]); - this["on" + sEventType] = runListeners; - } else { - var aElListeners = oEvtListeners.aEvts[nElIdx]; - if (this["on" + sEventType] !== runListeners) { - aElListeners.splice(0); - this["on" + sEventType] = runListeners; - } - for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) { - if (aElListeners[iLstId] === fListener) { return; } - } - aElListeners.push(fListener); - } - } else { - oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] }; - this["on" + sEventType] = runListeners; - } - }; - Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) { - if (!oListeners.hasOwnProperty(sEventType)) { return; } - var oEvtListeners = oListeners[sEventType]; - for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) { - if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; } - } - if (nElIdx === -1) { return; } - for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) { - if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); } - } - }; -} -``` +{{Compat}} -## See also +## 같이 보기 -- {{domxref("EventTarget.addEventListener()")}}. -- {{non-standard_inline}}{{domxref("EventTarget.detachEvent()")}}. +- {{domxref("EventTarget.addEventListener()")}} |