for문과 실행 컨텍스트, 클로져의 개념이 얽혀져 있는 상황을 공부해보자. 다음과 같이 세 가지 상황이 제시된다.
const funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function() { return i; }
}
for (let i = 0; i < 3; i++) {
console.log(funcs[i]());
}
// output : 0 1 2

const funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function() { return i; }
}
for (var j = 0; j < 3; j++) {
console.log(funcs[j]);
}
// output : 3 3 3

for(var i = 0; i < numbers.length; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
// output : 5 5 5 5 5
처음 봤을 때 위 함수의 동작에 있어서 이해가 안되는 부분 두 가지와 본인이 깨달은 바를 적어놓음
Q1. setTimeout 함수 내부에 전달되는 콜백 함수는 실행 컨텍스트가 삭제된 후에 호출되는데 어떻게 i 참조가 가능한거지?
A1. 클로저 구현을 위해 참조하고 있는 변수는 실행 컨텍스트가 삭제돼도 남아있음.
Q2. output이 0 1 2 3 4 가 나오도록 의도하기 위해서 let으로 키워드를 바꾸는게 무슨 의미가 있지?
A2. (1)번 예시코드에서 보았다시피, let 키워드는 각각의 렉시컬 환경을 생성하고, 각각의 값을 갖고 있으므로, 호출하는 함수 입장에서는 참조하고 있는 i가 전부 달라짐
Q3. setTimeout 함수 내부에 전달되는 콜백 함수는 실행 컨텍스트가 삭제된 후에 호출된다. 그러면 콜백 함수는 어디에 존재하는거지?
A3. 이 부분도 책에 나와있지 않아서 개인적인 생각을 적는다.
var 키워드로 선언된 전역 변수 및 함수 선언문을 제외한 let, const 키워드로 선언된 변수(아마 무명 함수 표현식도 포함될 것이라고 생각됨)는 선언적 환경 레코드에 평가 및 등록된다. 이후 비동기 함수의 콜백 함수로 전달되면, 테스크 큐에 있다가 이벤트 루프에 의해서 실행이 되어, 선언적 환경 레코드에 등록된 함수를 실행하여 실행 컨텍스트를 생성한다.
여기까지가 내 개인적인 생각이다.