본문 바로가기

CS/모던 자바스크립트 Deep Dive

40장 이벤트(1)

반응형

2023년 5월 5일 754p~767p

 

40.1 이벤트 드리븐 프로그래밍

이벤트 핸들러(event handler) : 이벤트가 발생했을 때 호출될 함수
이벤트 핸들러 등록 : 이벤트가 발생했을 때 브라우저에게 이벤트 핸들러의 호출을 위임하는 것.
이벤트 드리븐 프로그래밍(event-driven-programming) : 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식

함수를 언제 호출할지 알 수 없으므로 개발자가 명시적으로 "함수를 호출"하는 것이 아니라 "브라우저에게 함수 호출을 위임"한다.
ex) onclick event - 사용자가 언제 클릭할 지 알 수 없으므로 브라우저에게 특정함수(이벤트 핸들러)를 호출하도록 브라우저에게 위임(이벤트 핸들러 등록)할 수 있다.

 

40.2 이벤트 타입

이벤트 타입(event type) ? 이벤트의 종류를 나타내는 문자열
ex) click

 

40.3 이벤트 핸들러 등록

이벤트 핸들러는 이벤트가 발생했을 때 브라우저에 호출을 위임한 함수다.

이벤트 핸들러를 등록하는 방법은 3가지다.

 

1. 이벤트 핸들러 어트리뷰트 방식

이벤트 핸들러 어트리뷰트 값으로 함수 호출문 등의 문을 할당하면 이벤트 핸들러가 등록된다.

<button onClick="sayHi('Lee')">Click me!</button>
<script>
  function sayHi(name){
  	console.log(`Hi! ${name}`);
}
  </script>

주의할 점은 이벤트 핸들러의 어트리뷰트 값으로 함수 참조가 아닌 함수 호출문 등의 문을 할당한다는 것이다.

이벤트 핸들러 어트리뷰트 값은 사실 암묵적으로 생성될 이벤트 핸들러의 함수 몸체를 의미한다. 만약 이벤트 핸들러 어트리뷰트 값으로 함수 참조를 할당해야 한다면 이벤트 핸들러에 인수를 전달하기 곤란하다.

<!-- 이벤트 핸들러에 인수를 전달하기 곤란하다. -->
<button onclick="sayHi">Click me!</button>

위 방식은 바닐라 JS로 개발 시 사용하지 않는 것이 좋은데, 이는 HTML과 자바스크립트는 관심사가 다르므로 혼재하는 것보다는 분리하는 것이 좋기 때문이다.

하지만 모던 자바스크립트에서는 이벤트 핸들러 어트리뷰트 방식을 사용하는 경우가 있다. CBD(Component Based Development) 방식의 Angular/React/Svelte/Vue.js 같은 프레임워크/라이브러리에서는 이벤트 핸들러 어트리뷰트 방식으로 처리한다. CBD에서는 HTML, CSS, 자바스크립트를 관심사가 다른 개별적인 요소가 아닌, 뷰를 구상하기 위한 구성 요소로 보기 때문에 관심사가 다르다고 생각하지 않기 때문이다.

// Angular
<button (click)="handleClickc($event)">Save</button>

// React 
<button onClick={handleClick}>Save</button>

// Svelte 
<button on:click={handleClick}>Save</button>

// Vue.js
<button v-on:click="handleClick($event)">Save</button>

2. 이벤트 핸들러 프로퍼티 방식

window 객체와 Document, HTMLElement 타입의 DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티를 가지고 있다.
이벤트 핸들러 프로퍼티의 키는 이벤트 핸들러 어트리뷰트와 마찬가지로 onclick과 같이 on접두사와 이벤트 타입으로 이루어져 있다.

<!DOCTYPE html>
<html>
<body>
  <button>Click me!</button>
  <script>
    const $button = document.querySelector('button');

    // 이벤트 핸들러 프로퍼티에 이벤트 핸들러를 바인딩
    $button.onclick = function () {
      console.log('button click');
    };
  </script>
</body>
</html>

이벤트 핸들러를 등록하기 위해서는 이벤트를 발생시킬 객체인 이벤트 타깃(event target)과 이벤트 타입, 이벤트 핸들러를 지정할 필요가 있다.

이벤트 핸들러 프로퍼티 방식은 하나의 이벤트에 하나의 이벤트 핸들러만을 바인딩할 수 있다.
또한, 첫번째로 바인딩된 이벤트 핸들러는 두번째로 바인딩 된 핸들러에 의해 재할당되어 실행되지 않는다.

3. addEventListener 메서드 방식

EventTarget.prototype.addEventListener('eventType', functionName, [, useCapture] 메서드를 사용하는 방식도 있다.

useCapture : captrue 사용 여부(true : capturing 단계에서 이벤트 캐치, false : bubbling 단계에서 이벤트 캐치)

addEventListener 메서드 방식은 이벤트 핸들러 프로퍼티에 바인딩된 이벤트 핸들러에 아무런 영향을 주지 않는다. 

button.addEventListener('click', function(){
  	console.log('button click!');
});

addEventListener 메서드는 하나 이상의 이벤트 핸들러를 등록할 수 있다. 이 때 핸들러는 등록된 순서대로 호출된다. 

단, 참조가 동일한 이벤트 핸들러를 중복 등록하면 하나의 핸들러만 등록된다.

 

40.4 이벤트 핸들러 제거

EventTarget.prototype.removeEventListener 메서드를 사용한다.

removeEventListener 메서드에 아규먼트로 전달한 이벤트 핸들러는 addEventListener 메서드에 아규먼트로 전달한 등록 이벤트 핸들러와 동일해야 한다. 무명 함수를 이벤트 핸들러로 등록한 경우 제거할 수 없다.

단, 기명 이벤트 핸들러 내부에서 removeEventListener 메서드를 호출하여 이벤트 핸들러를 제거하는 것은 가능하다. 이때 이벤트 핸들러는 단 한 번만 호출된다.

button.addEventListener('click', function foo(){
  	console.log('button click');
  // 이벤트 핸들러를 제거한다. 따라서 이벤트 핸들러는 단 한 번만 호출된다. 
  button.removeEventListener('click', foo);
}

기명 함수를 이벤트로 등록할 수 없다면 호출된 함수, 즉 함수 자신을 가리키는 arguments.callee를 사용할 수도 있다.

button.addEventListener('click', function foo(){
  	console.log('button click');
  
  button.removeEventListener('click', arguments.callee);
}

arguments.callee는 코드 최적화를 방해하므로 strict mode에서 사용이 금지되므로 사용하지 않는 것이 좋다.

이벤트 핸들러 프로퍼티 방식으로 등록한 이벤트 핸들러는 removeEventListener 메서드로 제거할 수 없다.

button.onclick = handleClick;

// removeEventListener 메서드로 이벤트 핸들러를 제거할 수 없다. 
button.removeEventListener('click', handleClick);

// 이벤트 핸들러 프로퍼티에 null을 할당하여 이벤트 핸들러를 제거한다.
button.onclick = null;
반응형

'CS > 모던 자바스크립트 Deep Dive' 카테고리의 다른 글

40장 이벤트(3)  (0) 2023.05.08
40장 이벤트(2)  (0) 2023.05.06
39장 DOM(4)  (0) 2023.05.04
39장 DOM(3)  (0) 2023.05.03
39장 DOM(2)  (0) 2023.05.02