TIL: 클로저와 실행 컨텍스트, 렉시컬.. - 220702

Lumpen·2022년 7월 2일
0

TIL

목록 보기
76/242
post-thumbnail

클로저

var funcArr = [];
for (var i = 0; i < 10; i++) {
  funcArr.push(() => {
    console.log(i);
  });
}
for (var f of funcArr) {
  f();
}


클로저..
렉시컬 스코프를 통해 push 내부의 함수에서 i가
for에서 정의한 var i를 참조하고 있어
아래 for of문에서 i의 값을 계속 사용할 수 있다

하지만 for of 문에서 i를 사용할 때는 이미 i가 9까지 사용되고
i++로 후위 증감 연산자가 작동하면서
10이 된 결과를 계속 참조하게 된다

var funcArr = [];
for (var i = 0; i < 10; i++) {
  funcArr.push(
    ((i) => {
      return () => {
        console.log(i);
      };
    })(i) // 실행 인자로 i 전달
  );
}
for (var f of funcArr) {
  f();
}

이 경우 클로저를 전달하게 되면
push로 전달된 함수 내부에서 렉시컬 환경을 만들어서 계속 참조할 수 있다

var funcArr = [];
for (var i = 0; i < 10; i++) {
  funcArr.push((i) => {
    console.log(i);
  });
}
for (var f of funcArr) {
  f();
}

이 경우에는 push 함수로 전달되는 함수의 인자에 i가 선언되었지만 사용 시에 전달되는 매개 변수가 없기 때문에 실행 컨텍스트에서
선언된 인자에 대해 호이스팅이 일어나고 undefined가 전달된다

var funcArr = [];
for (let i = 0; i < 10; i++) {
  funcArr.push(() => {
    console.log(i);
  });
}
for (var f of funcArr) {
  f();
}

let으로 선언하게 되면
클로저를 전달한 방식과 같은 결과를 쉽게 낼 수 있다

let으로 선언한 것은 블록 레벨 스코프를 갖고 재할당이 가능하다
때문에 for문에서 사용될 때, let i가 0~9까지 각각의 블록 레벨의 실행 컨텍스트를 하나씩 갖게 된다
push에서 전달될 때 각각의 실행 컨텍스트를 가진 채 push하게 되기 때문에 0~9까지 출력된다

var로 선언하게 된다면 재선언, 재할당이되고 함수 레벨 스코프를 갖지만 함수 안에서 사용되지 않았다면
전역 스코프를 갖게 된다 (전역 변수의 프로퍼티가 됨)
전역 변수 내의 하나의 실행 컨텍스트로 0~9까지를 사용한다
때문에 첫 번째 경우에서 10이 전달되는 것

두 번째 경우에서는 내부에서 각각의 클로저를 새로 생성하기 때문에
0~9를 각각 출력할 수 있다

for 문에서의 var, let, const와 실행 컨텍스트, 클로져

  • var: 함수 레벨에서 사용되지 않으면 전역 스코프를 갖기 때문에 for문 에서 사용 시
    전역의 실행 컨텍스트에 변수가 등록되어 변수를 재활용 한다
    때문에 클로저를 사용할 경우 for 문이 다 끝난 10을 각각 참조하게 된다

  • let: 블록 레벨 스코프를 갖기 때문에 for문 안에서 매 실행마다 각각 i 하나씩의 블록 레벨 실행 컨텍스트에 매번 새로 등록된다

const: i가 각각의 실행 컨텍스트에서 사용되지만 재할당이 불가능 하기 때문에
후위 증감 연산자(i++)를 사용할 수 없으므로 for문의 변수로 사용될 수 없다

profile
떠돌이 생활을 하는. 실업자는 아니지만, 부랑 생활을 하는

0개의 댓글