예제 1 : function scope variable + closure
<script>
function runVarLoop() {
for (var i = 0; i < 3; i++) {
setTimeout(function() { alert(i); }, 1000 + i);
}
}
runVarLoop();
</script>
- setTimeout 이 콜백함수를 예약할 때, 각 콜백함수는 각 클로저를 생성합니다.
- 콜백함수 내의 변수 i 는 콜백함수가 선언된 렉시컬 환경에서의 i 를 의미합니다.
- 렉시컬 환경에서의 i 가 무엇인지 찾아가 보겠습니다.
- 렉시컬 환경에서의 i 는 for loop 내의 var 키워드로 선언되어 있습니다.
- var 키워드로 선언된 변수는 function scope 를 갖고 있으므로, runVarLoop 함수 내에서 선언된 것과 같습니다.
- 첫 번째 콜백함수의 렉시컬 환경의 i 는 runVarLoop 함수 내의 i 입니다.
- 두 번째 콜백함수의 렉시컬 환경의 i 도 runVarLoop 함수 내의 i 입니다.
- 세 번째 콜백함수의 렉시컬 환경의 i 도 runVarLoop 함수 내의 i 입니다.
- 각 콜백함수 실행 시점에는 모든 루프가 끝났으므로 렉시컬 환경의 i 값 3 이 출력됩니다.
예제 2 : block scope variable + closure
<script>
function runLetLoop() {
for (let i = 0; i < 3; i++) {
setTimeout(function() { alert(i); }, 1000 + i);
}
}
runLetLoop();
</script>
- setTimeout 이 콜백함수를 예약하는 시점에, 각 콜백함수는 각 클로저를 생성합니다.
- 콜백함수 내의 변수 i 는 콜백함수가 선언된 시점의 렉시컬 환경에서의 i 를 의미합니다.
- 렉시컬 환경에서의 i 가 무엇인지 찾아가보겠습니다.
- 렉시컬 환경에서의 i 는 for loop 내의 let 키워드로 선언되어 있습니다.
- let 키워드로 선언된 변수는 block scope 를 갖고 있으므로, for loop 의 블록 {} 내에서 선언된 것과 같습니다.
- 첫번째 콜백함수의 각 렉시컬 환경의 i 는 for 문의 첫번째 루프 block {} 에 선언된 i 이고 값은 0 입니다.
- 두번째 콜백함수의 각 렉시컬 환경의 i 는 for 문의 두번째 루프 block {} 에 선언된 i 이고 값은 1 입니다.
- 첫번째 콜백함수의 각 렉시컬 환경의 i 는 for 문의 세번째 루프 block {} 에 선언된 i 이고 값은 2 입니다.
- 각 콜백함수 실행 시점에는 각 렉시컬 환경의 i 의 값이 출력됩니다.