for문과 실행 컨텍스트, 클로져

wherehows·2021년 8월 17일
2

for문과 실행 컨텍스트, 클로져의 개념이 얽혀져 있는 상황을 공부해보자. 다음과 같이 세 가지 상황이 제시된다.

  1. for문의 변수 선언문에 let 키워드를 사용한 경우
  2. for문의 변수 선언문에 var 키워드를 사용한 경우
  3. for문 내에서 함수가 비동기로 실행되는 경우

1. for문의 변수 선언문에 let 키워드를 사용한 경우

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
  • for문의 변수 선언문에서 let키워드로 선언한 변수를 사용하면, for문이 실행될 때마다 새로운 렉시컬 환경을 생성
  • for문의 상위 스코프는 각각의 생성된 렉시컬 환경을 참조

2. for문의 변수 선언문에 var 키워드를 사용한 경우

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
  • var인 경우에는 설명이 나와있지 않아서, 새로운 렉시컬 환경이 생성되는지는 판단이 어려움. 본인이 생각하는 렉시컬 환경 동작에 기반하여 설명함.
  • for문의 블록은 독자적인 스코프를 형성한다. 그러므로, for문이 실행될 때마다 새로운 렉시컬 환경이 생성된다.
  • var 키워드로 선언된 변수는 window 객체에 등록되므로, 루프 렉시컬 환경의 i는 window 객체 참조.
  • 전역 환경 레코드의 선언적 환경 레코드에 저장된 함수 배열들은, 객체 환경 레코드에 등록된 i를 바로 참조함

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 키워드로 선언된 변수(아마 무명 함수 표현식도 포함될 것이라고 생각됨)는 선언적 환경 레코드에 평가 및 등록된다. 이후 비동기 함수의 콜백 함수로 전달되면, 테스크 큐에 있다가 이벤트 루프에 의해서 실행이 되어, 선언적 환경 레코드에 등록된 함수를 실행하여 실행 컨텍스트를 생성한다.
여기까지가 내 개인적인 생각이다.

0개의 댓글