[자바스크립트 딥다이브] 40장 이벤트

Bor·2021년 11월 1일
0

JS딥다이브

목록 보기
5/24

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

어플리케이션이 특정 타압의 이벤트에 대해서 반응해 어떤 일을 하고 싶다면 해당 타입의 이벤트가 발생 시 호출될 함수를 브라우저에게 알려 호출을 위임한다. 이때 이벤트 발생 시 호출 함수를 이벤트 핸들러(evnet handler)라 하고, 호출을 위임하는 것을 이벤트 핸들러 등록이라 한다. 근데 언제 호출할지 개발자는 알 수 없으므로 우리가 명시적으로 호출하는 게 아니라 브라우저에게 함수 호출을 위임한다.

이처럼 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식을 이벤트 드리븐 프로그래밍(event-driven programing)이라 한다.


40.2 이벤트 타입

https://developer.mozilla.org/en-US/docs/Web/Events 참조


40.3 이벤트 타입

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

40.3.1 이벤트 핸들러 어트리뷰트 방식

HTML의 요소의 어트리뷰트 중에는 이벤트에 대응하는 이벤트 핸들러 어트리뷰트가 있다. 보통 on 접두사와 타입으로 이뤄져 있으며 이에 함수 호출문 등의 statement를 할당하면 이벤트 핸들러가 등록된다.

주의할 점은 어트리뷰트의 값으로 함수 참조가 아니라 함수 호출문 등의 statement을 할당한다는 것. 이후에 살펴볼 <이벤트 핸들러 프로퍼티 방식>에서는 DOM 노드의 이벤트 핸들러 프로터이에 함수 참조를 할당한다. 이벤트 핸들러 어트리뷰트 방식은 오래된 방식으로 더는 사용하지 않는 것이 좋다.

HTML과 자바스크립트의 역할이 다르기 때문! 그러나 CBD(Coponent Based Development)방식의 Angular/React/Vue.js 같은 프레임워크/라이브러리에서는 위 방식으로 이벤트를 처리한다. 왜냐면 뷰를 구성하기 위한 구성 요소로 보기에 관심사가 다르지 않다고 생각하기 때문이다.

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

DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티 소유한다. 이벤트 핸들러 프로퍼티에 함수를 바이딩하면 이벤트 핸들러가 등록된다.

  • $button: 이벤트 타깃
  • onclick: on + 이벤트 타입
  • function: 이벤트 핸들러

앞서 살펴본 어트리뷰트 방식도 결국 DOM 노드 객체의 이벤트 핸들러 프로퍼티로 변환되므로 결과적으로 프로퍼티 방식과 동일하다고도 볼 수 있다. 프로퍼티 방식은 앞선 방식과 달리 HTML, JS가 뒤섞이는 것을 방지할 수 있지만 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다.


40.3.3 addEventListener 메서드 방식

DOM level2에서 도입.

  • EventTarget.addEventListener('eventType', functionName [,useCapture]);
    마지막 매개변수에는 이벤트를 캐치할 이벤트 전파 단계를 지정한다.(캡처링 혹은 버블링) 생략하거나 false를 지정하면 버블링 단계에서 이벤트를 캐치. true를 지정하면 캡처링 단계에서 이벤트를 캐치.

    이 방식은 이벤트 핸들러 프로퍼티에 바인딩된 이벤트 핸들러에 아무런 영향도 주지 않는다. 따라서 버튼 요소에서 클릭 이벤트가 발생하면 2개의 핸들러가 모두 호출되며 등록 순서대로 호출된다.

40.4 이벤트 핸들러 제거

addEventListener 메서드에 전달한 인수와 removeEventListener 메서드에 전달한 인수가 일치하지 않으면 이벤트 핸들러가 제거되지 않는다. 그렇기 때문에 무명 함수를 이벤트 핸들러로 등록한 경우 제거할 수 없으며 제거하려면 이벤트 핸들러의 참조를 변수나 자료구조에 저장하고 있어야 한다.


40.5 이벤트 객체

이벤트가 발생하면 이벤트에 관련한 다양한 정보를 담고 있는 이벤트 객체가 동적으로 생성. 이벤트 객체는 핸들러의 첫 번째 인수로 전달된다.

클릭 이벤트에 의해 생성된 이벤트 객체는 이벤트 핸들러의 첫 인수로 전달되기 때문에 매개변수 e에 암묵적으로 할당. 이는 브라우저가 이벤트 핸들러를 호출할 때 이벤트 객체를 인수로 전달하기 때문. 따라서 이벤트 객체를 전달받으려면 이벤트 핸들러를 정의할 때 이벤트 객체를 전달받은 매개변수를 명시적으로 선언해야 한다.

40.5.1 이벤트 객체의 상속 구조

이벤트 객체는 다음과 같은 상속 구조를 갖는다. 이처럼 이벤트가 발생하면 암묵적으로 생성되는 이벤트 객체도 생성자 함수에 의해 생성된다.

그리고 생생된 이벤트 객체는 생성자 함수와 더불어 생성되는 프로토타입으로 구성된 프로토타입 체인의 일원이된다. 예를 들어, click 이벤트가 발생하면 암묵적으로 생성되는 MouseEvent 타입의 이벤트 객체는 다음과 같은 타입 체인의 일원이 된다.

40.6 이벤트 전파

DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 ㅗㅇ해 전파된다. 이를 이벤트 전파(event propagation)라고 한다.

Button을 클릭하면 클릭 이벤트가 발생한다. 이 때 생성된 이벤트 객체는 이벤트를 발생시킨 DOM 요소인 이벤트 타깃(event target)을 중심으로 DOM 트리를 통해 전파된다.

  • Capturing phase: 이벤트가 상위요소에서 하위 요소 방향으로 전파
  • Bubbling phase: 이벤트가 하위요소에서 상위 요소 방향으로 전파


li요소를 클릭하면 클릭 이벤트가 발생하여 클릭 이벤트 객체가 생성되고 클릭된 li 요소가 이벤트 타깃이 된다. 이 때 클릭 이벤트 객체는 window에서 시작해서 이벤트 타깃 방향으로 전파된다. 이것이 캡처링 단계. 이후 이벤트 객체는 타깃에 도달하며 이것이 타깃 단계. 이후 이벤트 객체는 이벤트 타깃에서 시작해서 window 방향으로 전파된다. 이것이 버블링 단계이다.


40.7 이벤트 위임


이벤트 위임을 통해 하위 DOM 요소에서 발생한 이벤트를 처리할 때 주의할 점은 상위 요소에 이벤트 핸들러를 등록하기에 이벤트 타깃, 즉 이벤트를 실제 발생시킨 DOM요소가 개발자가 기대한 게 아닐 수도 있다. 위의 예제의 경우 ul#fruits 요소에 바인딩된 이벤트 핸들러는 ul#fruits의 모든 하위 요소에 반응한다.


40.8 DOM 요소의 기본 동작 조작

40.8.1 DOM 요소의 기본 동작 중단

DOM 요소는 저마다 기본 동작이 있다. a의 저장된 링크로 이동과 같이. 이벤트 객체의 preventDefault 메서드는 이러한 DOM 요소의 기본 동작을 중단시키며 하위 DOM 요소의 이벤트를 개별적으로 처리하기 위해 이벤트의 전파를 중단시킨다.

40.8.2 이벤트 전파 방지

이벤트 객체의 stopPropagation 메서드는 이벤트 전파를 중지시킨다.


위 예제를 살펴보면 상위 DOM 요소인 container 요소에 이벤트를 위임했다. 따라서 하위 DOM 요소에서 발생한 클릭 이벤트를 상위 DOM 요소인 container가 캐치해서 처리한다. 근데 btn2는 자체적으로 이벤트를 처리한다. btn2 요소는 자신이 발생시킨 이벤트가 전파되는 것을 중단하여 자신에게 바인딩된 이벤트 핸들러만 실행되도록 한다.


40.9 이벤트 핸들러 내부의 this

40.9.1 이벤트 핸들러 프로퍼티와 addEventListener 메서드 방식

위 두 방식 모두 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다. 즉 이벤트 핸들러 재부의 this는 이벤트 객체의 currentTarget 프로퍼티. 그러나 화살표 함수로 정의한 이벤트 핸들러 내부의 this는 상위 스코프의 this를 가리킨다. 화살표 함수는 함수 자체의 this 바인딩을 갖지 않는다.

클래스에서 이벤트 핸들러 바인딩하는 경우 this에 주의해야 한다.

위 예제의 increase 메서드 내부의 this는 클래스가 생성할 인스턴스를 가리키지 않는다. 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리키기 때문에 increase 메서드 내부의 this는 this.$button을 가리킨다. 따라서 increase 메서드를 이벤트 핸들러로 바인딩할 때 bind 메서드를 사용해 this를 전달해 increase 메서드 내부의 this가 클래스가 생성할 인스컨스를 가리키도록 해야 한다.

this.$button.onclick = this.increase.bind(this);

40.10 커스텀 이벤트

40.10 커스텀 이벤트 생성

이벤트가 발생하면 암묵적으로 생성되는 이벤트 객체는 발생한 이벤트의 종류에 따라 이벤트 타입이 결정된다. 하지만 Event, UIEvent, MouseEvent 같은 이벤트 생성자 함수를 호출하여 명시적으로 생성한 이벤트 객체는 임의의 이벤트 타입을 지정할 수 있다. 이처럼 개발자의 의도로 생성된 이벤트를 커스텀 이벤트라고 한다.

const keyboardEvent = new keyboardEvent('boram');
console.log(keyboardEvent.type); boram

생성된 커스텀 이벤트 객체는 버블링되지 않으며 preventDefault 메서드로 취소할 수 없다. 즉, 커스텀 이벤트 객체는 bubbles와 cancelable 프로퍼티의 값이 false로 기본 설정된다.

0개의 댓글