브라우저는 처리해야할 특정 사건이 발생하면 이를 감지하여 이벤트를 발생시킨다.
특정 타입의 이벤트에 반응하여 어떤 일을 수행하도록 하고 싶다면, 이벤트가 발생했을 때 호출될 함수(=이벤트 핸들러) 를 브라우저에게 알려 호출을 위임(=이벤트 핸들러 등록)한다.
이벤트 타입은 이벤트의 종류를 나태내는 문자열이다. 이벤트 타입은 200여가지가 있는데 MDN 이벤트 참조 에서 확인해볼 수 있다. 버블링 될 수 있는 지, 연속해서 발생할 수 있는지, 특정 객체에서만 발생할 수 있는 지(ex. 'resize' 이벤트는 오직 window 이벤트에서만 발생한다! )에 대한 여부를 잘 확인해두자
이벤트를 등록하는 방법은 이벤트 핸들러 어트리뷰트 방식, 이벤트 핸들러 프로퍼티 방식, addEventListener 메서드 방식이 있다.
<button onclick="sayHi('yeojin')"> </button>
<script>
function sayHi(name) {
console.log(`Hi ${name}`);
}
</script>
function onclick(event) {
sayHi('yeojin');
}
window
, document
, HTMLElement
와 같은 DOM 노드 객체는 이벤트 핸들러 프로퍼티를 가지고 있다.
이벤트 핸들러 프로퍼티에 함수를 바인딩하여 이벤트 핸들러를 등록할 수 있다.
이벤트 등록 시 이벤트를 발생시킬 객체(이벤트 타깃), 이벤트의 종류를 나타내는 문자열(이벤트 타입), 이벤트 핸들러를 지정해주어야한다.
단, 해당 방식은 하나의 이벤트 핸들러만 바인딩 할 수 있다. 여러번 바인딩 할 경우 마지막에 바인딩된 이벤트 핸들러만 실행된다.
const button = document.querySelector('button');
button.onclick = function () {
console.log('Hi yeojin');
}
EventTarget.prototype.addEventListener
메서드를 사용해 이벤트를 등록할 수 있다.EventTarget.addEventLisener('eventType', functionName,[,useCapture])
const button = document.querySelector('button');
button.addEventListener('click', function () {
console.log('Hi yeojin');
})
const button = document.querySelector('button');
button.onclick = function () {
console.log('Hi yeojin 1');
}
button.addEventListener('click', function () {
console.log('Hi yeojin 2');
})
// Hi yeojin
// Hi yeojin
const button = document.querySelector('button');
button.addEventListener('click', function () {
console.log('Hi yeojin 1');
})
button.addEventListener('click', function () {
console.log('Hi yeojin 2');
})
// Hi yeojin
// Hi yeojin
const button = document.querySelector('button');
const handleClick = () => console.log('Hi yeojin');
button.addEventListener('click', handleClick);
button.addEventListener('click', handleClick);
// Hi yeojin
EventTarget.prototype.removeEventListener
메서드를 사용해 제거할 수 있다. 단, addEventListener 메서드에 전달한 인수와 removeEventListener 메서드에 전달한 인수가 일치하여야한다. const button = document.querySelector('button');
const handleClick = () => console.log('Hi yeojin');
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick,true); // 실패
const button = document.querySelector('button');
button.addEventListener('click', () => console.log('Hi yeojin')); // 제거 불가
const button = document.querySelector('button');
button.addEventListener('click', function foo() {
console.log('Hi yeojin'));
button.removeEventListener('click', foo);
});
arguments.callee
를 사용할 수 있지만 코드 최적화를 방해하므로 strict mode 에서 사용이 금지된다. const button = document.querySelector('button');
button.addEventListener('click', function foo() {
console.log('Hi yeojin'));
button.removeEventListener('click', arguments.callee);
});
<button onclick="handleClick(this)"> </button>
<script>
function handleClick(foo) {
console.log(this); // window
console.log(foo); // 이벤트를 바인딩한 button 요소
}
</script>
const button = document.querySelector('button');
button.addEventListener('click', function foo(e) {
console.log(this);
console.log(e.currentTarget); // button
console.log(this === e.currentTarget); // true
});
const button = document.querySelector('button');
button.addEventListener('click', e => {
console.log(this); // window
console.log(e.currentTarget); // button
console.log(this === e.currentTarget); // false
});
// Bad
class App {
constructor() {
this.count = 0;
this.button = document.querySelector('button');
// increase 메서드를 이벤트 핸들러로 등록
this.button.onclick = this.increase;
}
increase() {
// 이벤트 핸들러 내부의 this 는 클래스가 생성할 인스턴스가 아니라 DOM 요소를 가리키기 때문에
// this.button 은 this.button.button 이 된다.
this.button.textContent = ++this.count;
}
}
// Good
class App {
constructor() {
this.count = 0;
this.button = document.querySelector('button');
// bind 메서드를 사용해 this 를 전달하여 메서드 내부 this 가 클래스가 생성할 인스턴스를 가리키도록 해야한다.
this.button.onclick = this.increase.bind(this);
}
increase() {
this.button.textContent = ++this.count;
}
}
// Good
class App {
constructor() {
this.count = 0;
this.button = document.querySelector('button');
// increase 메서드를 이벤트 핸들러로 등록
this.button.onclick = this.increase;
}
// 클래스 필드에 할당한 화살표 함수를 이벤트 핸들러로 등록하여 이벤트 핸들러 내부의 this 가 인스턴스를 가리키도록 한다.
// 프로토타입 메서드가 아닌 인스턴스 메서드가 된다.
increase =() => this.button.textContent = ++this.count;
}