Javacsript si Wierd - 2-3. Block Scope-thumbnail

Javacsript si Wierd - 2-3. Block Scope

Block Scope
452

Block Scope

for(var i=0; i<10; i++){
  console.log(i);
}

console.log(i); // 10


loading = false;

if(!loading){
  var limit = 5;
  var result = makeSomething(limit);

  console.log(result);
}

console.log(limit); // 5

바라기로는 for문이나 if문 모두 block scope였으면 좋겠지만, 안타깝게도 var i=0;, var limit = 5; 등등이 global scope에 선언된다. 슬픈 일이다. 하지만 다행히도 ES6부터 우리에게 letconst가 나타났다.

for(let i=0; i<10; i++){
  console.log(i);
}
console.log(i); // Uncaught ReferenceError: i is not defined


loading = false;

if(!loading){
  const limit = 5;
  const result = makeSomething(limit);

  console.log(result);
}

console.log(limit); // Uncaught ReferenceError: limit is not defined

이런 형식이 조금은 명시적이지 못하다는 느낌이 있다면 아래와 같이 해도 좋다.

if(!loading){
  {
    const limit = 5;
    const result = makeSomething(limit);

    console.log(result);
  } // explicit block
}

명시적으로(물론 자주 볼 수 있는 코드 형태는 아니지만) scope가 표현되어 훨씬 이해하기에 좋다.

Block scope를 해주면 좋은 점 중 하나는 Garbage collection과도 관련이 있다. 아래의 코드를 보자.

function bigProcess(bigData) {
  /* ... */
}

var reallyBigData = { /* ... */ };

bigProcess(reallyBigData);

var btn = document.querySelector('#btn');
btn.addEventListener('click', function clickHandler(e) {
  /* ... */
}, false);

clickHandler 함수는 reallyBigData가 필요가 없음에도 같은 scope에 있기 때문에 reallyBigData가 memory를 잡아먹는 것을 감수해야만 한다. 하지만 코드를 아래와 같이 바꾼다면?

function bigProcess(bigData) {
  /* ... */
}

{
  let reallyBigData = { /* ... */ };

  bigProcess(reallyBigData);
}

var btn = document.querySelector('#btn');
btn.addEventListener('click', function clickHandler(e) {
  /* ... */
}, false);

이제 "Engine"clickHandler에게 reallyBigData가 필요없다는 것을 눈치챌 것이다. bigProcess(reallyBigData)가 실행된 뒤, 메모리를 많이 잡아먹던 reallyBigData는 곧바로 수거될 것이다.


참고 서적 : 카일 심슨, 2017, 한빛미디어, 『YOU DON'T KNOW JS: 타입과 문법, 스코프와 클로저』