크롬 확장 프로그램을 개발하면서 이벤트에 대해서 더 자세하게 알아야 할 필요가 있다는 것을 느끼고 이벤트에 대해서 조금 더 자세하게 공부를 하려고 한다.
이벤트(event)란 프로그래밍하고 있는 시스템에서 일어나는 사건(action) 혹은 발생(occurrence)인데, 그것들에 어떠한 방식으로 응답할 수 있도록 시스템이 말해주는 것이다.
시스템은 이벤트가 발생될 때 몇몇 종류의 신호를 생산(produce, 또는 발생 (fire)) 시키고, 이벤트가 발생됐을 때 사건이 자동적으로 취해질 수 있는 메커니즘을 제공한다. (출처 : MDN 이벤트 입문)
자바스크립트는 이벤트가 발생했을 때 이벤트에 맞는 동작을 처리할 수 있도록 콜백함수를 제공하고 이는 이벤트가 발생했을 때 자동적으로 실행되며 이러한 함수를 이벤트 핸들러라고 한다.
이벤트 핸들러를 등록하는 방법은 3가지가 있다.
HTML 요소의 어트리뷰트 중에는 이벤트에 대응하는 이벤트 핸들러 어트리뷰트가 있다. 이때 주의해야 할 점은 함수 참조가 아닌 함수 호출문 등의 문을 할당해야 한다.
<body>
<button onclick="say('hello world')">Click me!</button>d
<script>
function say(str) {
alert(str);
}
</script>
</body>
다만, 이 방법은 HTML과 자바스크립트는 관심사가 다르므로 혼재하는 것보다 분리하는 것이 좋다
window 객체와 Document, HTMLElement 타입의 DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티를 가지고 있다.
const $button = document.querySelector('button');
$button.onclick = function() {
alert('Hello World');
}
이벤트 핸들러 프로퍼티 방식은 하나의 이벤트에 하나의 이벤트 핸들러만 바인딩할 수 있다.
const $button = document.querySelector('button');
$button.onclick = function () {console.log('click');} // 첫 번째로 바인딩 된 이벤트 핸들러는 무시된다.
$button.onclick = function () {console.log('click2');}
EventTarget.addEventListener(eventType, callback, [, useCapture]);
위 형식을 가지고 있으며 useCapture의 경우 이벤트를 캐치할 이벤트 전파 단계(캡쳐링 또는 버블링)를 지정한다. 생략하거나 false를 지정하면 버블링 단계에서 이벤트를 캐치하고, true를 지정하면 캡처링 단계에서 이벤트를 캐치한다
또한 이벤트 핸들러 프로퍼티 방식과는 다르게 2개가 바인딩이 된다면 2개의 이벤트 핸들러가 모두 실행된다.
const $button = document.querySelector('button');
$button.addEventListener('click',function() { console.log('click');})
$button.addEventListener('click', function () {console.log('click2');})
이벤트 핸들러를 제거하기 위해서는 EventTarget.removeEventListener를 사용한다. addEventListener의 매개변수와 동일한 인수를 전달할 수 있으며 여기서 가장 중요한 것이 addEventListener에서 전달한 인수와 removeEventListener에 전달되는 인수가 동일해야 이벤트 핸들러를 제거할 수 있다. 인수를 동일시 시켜야 하기 때문에 함수에 대해서 참조를 할 수 있어야 제대로 삭제할 수 있다. 즉, 무명함수의 경우 등록할 수 있어도 제거를 할 수 없다. 다만 이벤트 핸들러 내부에서 등록을 해제 할 수는 있다. 만약에 이벤트를 프로퍼티 속성으로 바인딩했다면 다시 그 속성에 null을 바인딩하여 참조를 없애버리면 자바스크립트 가비지 컬렉터를 통해 삭제할 수 있다.
const $button = document.querySelector('button');
const handleClick = function () {console.log('click')}
$button.addEventListener('click',handleClick);
// 이 경우에는 바로 안에서 삭제가 가능하다.
$button.addEventListener('click',function () {
console.log('remove click');
$button.removeEventListener('click',arguments.callee); // arguments callee는 함수 자신을 가리킨다.
});
$button.removeEventListener('click',handleClick); // 삭제 됨
$button.removeEventListener('click', handleClick, true); // 삭제 안됨
$button.removeEventListener('click',() => {console.log('click');}) // 삭제 안됨