JavaScript의 타이머와 컨텍스트 손실
타이머를 이벤트 핸들러에서 사용할 때 컨텍스트 손실 문제가 우리를 기다리고 있습니다. 예제를 통해 살펴보겠습니다.
우리에게 다음과 같은 입력 필드가 있다고 가정합니다:
<input id="elem" value="text">
이 입력 필드를 클릭할 때 익명 함수가 실행되고, 이 함수 내부에서 1초마다 콘솔에 무언가를 출력하는 타이머가 시작된다고 가정합니다:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // 콘솔에 무언가 출력
}, 1000);
});
지금까지는 모든 것이 정상적으로 작동합니다.
하지만 이제 콘솔에 입력 필드의 value를
출력하고 싶다고 하면 놀라운 일이 기다리고 있습니다:
콘솔에 undefined가 출력될 것입니다:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // undefined가 출력됩니다
}, 1000);
});
문제는 함수 안에 함수가 있는 구조에 있습니다:
클릭 시 호출되는 외부 익명 함수와,
타이머가 시작하는 내부 익명 함수가 있습니다.
외부 함수에서 this는 입력 필드를 가리키지만,
내부 함수에서는 그렇지 않습니다.
컨텍스트 손실이 발생한 것입니다.
이전 강의에서처럼 콘솔에 오류가 발생하지 않고
undefined가 출력되는 이유는 무엇일까요?
setInterval을 통해 호출되는 함수 내부의
this는 window를 가리키기 때문입니다.
이는 우리가 window 객체의 value 속성을
읽으려고 시도한다는 것을 의미합니다. 즉, window.value처럼요.
하지만 window에는 그런 속성이 없기 때문에
(오류가 아닌) undefined를 얻는 것입니다.
self를 도입하여 문제를 해결해 보겠습니다:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
다음과 같은 코드가 주어졌다고 가정합니다:
<input type="button" id="elem" value="1">
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
this.value = Number(elem.value) + 1;
}, 1000);
});
코드 작성자는 버튼을 누를 때마다
이 버튼의 값이 1초마다 1씩
증가하기를 원했습니다.
그러나 버튼을 눌러도 아무 일도
일어나지 않습니다.
코드 작성자의 오류를 수정하십시오.
작성자의 오류가 왜 발생했는지 설명하는
텍스트를 작성하십시오.