function outer() {
var a = 2;
function inner() {
console.log(a);
}
return inner;
}
var func = outer();
func(); // 2
스코프 외부에서 inner()
가 실행되도 해당 스코프를 기억하기 때문에 2를 출력하게 된다. 즉, 여기서 클로저는 inner()
가 되며 func
에 담겨 밖에서도 실행되고 렉시컬 스코프를 기억한다.
function func() {
for (var i=1; i<5; i++) {
setTimeout(function() { console.log(i); }, i*500);
}
}
func(); // 5 5 5 5
위가 위도한 바는 1 2 3 4
출력이다. 그렇지만 결과는 5 5 5 5가 나온다.
setTimeout() 을 반복문 안에서 돌리면 콜백함수가 계속해서 task queue에 쌓이게 되고 반복문이 끝나고 나서 call stack으로 돌아와서 실행된다. 콜백함수는 클로저이기 때문에 상위 스코프에게 i 의 값을 물어보고 상위 스코프인 func 의 스코프에선 i 가 5까지 증가했기 때문에 5가 4번 출력된다.
function func() {
for (var i=1; i<5; i++) {
(function (j) {
setTimeout(function() { console.log(j); }, j*500);
})(i);
}
}
func(); // 1 2 3 4
즉시실행함수 표현식
으로 감싸서 해결한다.
function func() {
for (let i=1; i<5; i++) {
setTimeout(function() { console.log(i); }, i*500);
}
}
func(); // 1 2 3 4
블록 스코프
를 갖는 let 을 사용하면 for 문 내의 새로운 스코프를 갖기 때문에 매 반복마다 새로운 i 가 선언되고 반복이 끝난 이후의 값으로 초기화가 된다.