스코프와 비동기적 실행
function countdown() {
let i; // i를 for문 밖에서 선언
console.log("Countdown");
for(i = 5; i >= 0; i--) {
setTimeout(() => {
console.log(i === 0 ? "GO!" : i);
}, (5-i)*1000);
}
countdown();
}
코드를 보면 5에서 부터 카운트 다운되는, 아래와 같은 결과를 예상하지만,
5
4
3
2
1
GO!
실제 결과는 아래와 같다.
-1
-1
-1
-1
-1
-1
원하는 결과를 얻으려면 코드를 아래와 같이 수정해야 한다.
function countdown() {
console.log("Countdown");
for(let i = 5; i >= 0; i--) { // i를 for문 선언부에서 선언
setTimeout(() => {
console.log(i === 0 ? "GO!" : i);
}, (5-i)*1000);
}
countdown();
}
디버깅해보면, 순서가 이렇다.
console.log()
를 출력한다for문을 돌면서,
i
가0
까지 반복되며(최종적으로 i는 0에서 -1 되어 -1이 된다 -반복은 더 이상 안되지만)setTimeout()
을 실행한다.반복이 끝나면, 콜백 큐에 들어있던 함수들이 다시 콜스택으로 들어온다.
첫번째 코드의 경우, 콜백함수가
i = -1
을 참조한다.두번째 코드의 경우, 처음 들어온 콜백함수는
i = 5
, 두번째 함수는i = 4
... 식으로 참조한다. 첫번째 코드와는 다르게 i가 실행되었을 때의 값이 기억되고 있다
왜 그럴까
클로저가 형성되며 콜 스택이 비워지고 콜백함수가 실행될 시기엔 이미 i가 모두 연산이 끝난 이후다. for문 블록 내부에 let을 선언해줌으로써, 함수가 실행될 당시 올바른 i를 참조할 수 있도록 하면 해결된다. (변수가 묶인다)
참고 자료
https://medium.com/@js_tut/the-visual-guide-to-javascript-variable-definitions-scope-abfb86edad
Last updated
Was this helpful?