[JavaScript] block-level scope란 (let vs var)

·

2 min read

글의 목적

JavaScript의 block-level scope란 무엇인지 구체적인 사례를 통해 이해한다.

block-level scope의 존재를 알게 된 사례

React로 간단한 Todo-list 앱을 제작하고 있었다. 각 행마다 내용과 완료 버튼이 있는데, 이 때 이 완료 버튼 클릭 시 호출하는 함수인 'handleDone'에 관한 고민이 있었다.

quests.map((quest, i) => (
  <QuestRow
    key={i}
    quest={quest}
    handleDone={() => {
      handleDone(i);
    }}
    handleDelete={() => {
      handleDelete(i);
    }}
  />
));

map을 사용하여 각 Todo 항목마다 한 행을 담당하는 Component를 뱉도록 한 코드이다. 그런데 여기서 () => handleDone(i)i가... 어떻게 살아있는거지...? 어떤 값을 참조하는거지? 하는 의문이 들었다.

실험1

let funcs = [];
let a = 1;
while (a <= 4) {
    funcs.push(() => console.log(a));
    a++;
}
for (const f of funcs) f();

위 코드의 실행 결과로 1, 2, 3, 4를 예상했지만... 5, 5, 5, 5 였다. 그렇다. 어찌보면 당연하다. f를 호출하는 시점에서 각 f가 참조하는 변수 a의 값은... 5이니까...! 그런데 저 위의 react 코드는 어떻게 각 i를 기억?하는 것일까?

실험2

let funcs = [];
let a = 1;
while (a <= 4) {
    let local_a = a;
    funcs.push(() => console.log(local_a));
    a++;
}
for (const f of funcs) f();

여기서 local_a라는, block 내에서 let 키워드로 선언한 변수에 a값을 넣어주고, 각 f가 local_a를 참조하게 하면...! 1, 2, 3, 4를 출력하는 것을 볼 수 있다! local_a는 각 loop의 block에서만 유효한 변수이기에 이렇게 동작하는 것이다. 추가로, 각 block 내에서 선언된 변수들은 (참조되고 있는 한) 메모리에 계속 남아있는 다는 것을 알 수 있었다.

  • local_a를 let이 아닌 var로 선언해줄 경우, global 변수가 되어 다시 5, 5, 5, 5를 출력하게 된다.

결론

간단한 실험을 통해 block-level scope가 무엇인지 이해할 수 있었다. 또한 let과 var의 scope 차이 또한 알게 되었다.