JavaScript - Scope와 Hoisting


Block Scope는 ES6에서 처음 등장하는 Scope이다.

JavaScript에는 원래 함수 Scope가 존재했다.

Scope : 범위. 유효공간. 살수 있는 공간. 허용공간, 허용범위

함수 스코프는 즉 함수에 의해서 생기는 범위이다. 이 범위는 변수의 유효범위이다. 원래 ES5까지는 여기까지 존재했다. 이 스코프가 생기는 것이 함수에 의해서만 생긴다는 뜻이다.

근데 이제는 블락스코프가 생겼다.

Block Scope는 block에 의해 생기는 유효범위이다. 이 블락은 {}을 의미한다. 즉 {}에 의해서 변수의 유효범위까지 결정된다는 것이다.

Block Scope

기존에는 var를 썼지만 ES6부터는 let, const와 같이 변수 선언하는 애들이 더 많이 생겼다.

만약

{
  let a = 10
}
console.log(a)

가 된다면 결과는 a is not defined라고 뜬다. 왜냐하면 a는 블락 스코프(유효범위)안에서 선언이 되었기 때문이다.

근데 만약

{
  var v = 'blue'
}
console.log(v)

라고 하면 v는 blue라고 출력된다. var는 스코프의 영향을 받지 않기 때문이다. let만 블락스코프의 영향을 받는다.

let, const만 블럭스코프의 영향을 받는다.

var는 영향을 받지 않는다.

Hoisting

스코프는 중괄호에 의해 영향을 받는다.

if(true){
}

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

while(true){
}

switch(a){
  case: break;
}

위에 있는 애들은 if 문, for 문과 같이 ~~문이라 부른다. 이 문은 ‘문단’을 의미한다.

문단과 반대되는 거는 식(expressiont)으로 값이 될 수 있는 경우가 된다. 예로는 10+20, ‘a’+’b’와 같이 값이 될 수 있는 것들이 여기에 해당된다.

모든 데이터는 값, 식, 문 중에 하나이다. 값과 식은 동일하게 간주가 된다. 문단은 결과를 리턴하지 않는다.

그니까 if 문같은 것들을 실행하고 끝이고 반환해주는 값 같은 거는 없다.

따라서 문단 자체가 하나의 block-scope가 된다.

if(true){
  let a = 10
  if(true){
    console.log(a)
    const a = 20
  }
  console.log(a)
}

위의 코드에서 만약 hoisting이 된다면 a는 undefined가 출력될 것이다. hoisting이 안된다면 a는 10이 나올 것이다.

결과로는 undefined가 나온다. 이와 관련된 것으로 TDZ(Temporal Dead Zone. 임시 사각지대)를 얘기할 수 있다.

위의 코드는 TDZ에 걸린다. let이나 const에 대해서 이 변수를 실제 선언한 위치에 오기까지는 그 변수를 호출할 수 없다.

위에서부터 아래로 내려가야 하는데 실수로 아래서 var로 써놓은 변수를 위에서 호출했는데 오류가 안나는 상황이 생길 수 있으므로 hoisting은 중요하다.

Hoisting을 다시 정리하면 다음과 같다.

기존 var 시스템에서는 변수명만 위로 끌어올리고 -> undefined를 할당한다.

근데 let 이나 const를 쓰면 변수명만 위로 끌어올리고 -> 끝이다. 즉 hoisting을 해서 a의 존재를 블럭 스코프 안에서 인식하고 있지만, undefined 할당하는 과정이 빠진 것이다.

Hoisting을 하지만, TDZ라는 것이 존재하여 할당을 하지 않는 것으로 이해하면 될 것 같다.