es6이전에는 변수를 선언할 때 var를 이용하여 변수를 선언하였다.
var의 경우엔 function 단위의 scope를 가진다. 이는 함수안에서만 선언 될 경우에 scope를 가지는 것을 의미한다. if나 for문안에서 var를 선언할 경우 해당 변수는 scope를 if나 for가 아닌 상위의 함수(없으면 전역)를 scope로 가지게 된다.
function func() {
var a = 1; // func scope
}
console.log(a) // error
for(var i =0; i<10;i++) {
var b = 2; // 전역 scope
}
console.log(b) // 2
b가 scope가 전역으로 설정이 되면서 다음과 같이 이상한 코드가 발생하게 된다.
function scope와 호이스팅 개념이 만나 다음과 같은 원리로 동작된다고 생각하면 된다(실제로 이렇게 동작하진 않는다)
var b;
function func() {
var a;
a = 1;
}
console.log(a) // error
for(var i =0; i<10;i++) {
b = 2;
}
console.log(b) // 2
let과 const는 es6 이후에 선언 되었다. 위에 처럼 이상한 코드가 실제로 코드를 작성하는 입장에서는 헷갈릴 만한 요소가 많아 block scope로 설정 되었다.
blcok scope는 중괄호 단위로 스코프가 설정되는 것으로 이해하면 된다. 그로인해 for문과 if문안에서 선언할 경우에는 if문과 for문안에서만 사용가능한 변수로 설정이 된다.
const b = 1;
for(var i =0; i<10; i++) {
coonsole.log(b) // error
const b = 2;
}
이렇게 보면 const, let에선 호이스팅이 일어나지 않는 것처럼 보인다.
하지만 호이스팅이란 개념은 결국 실행컨텍스트로 인해 발생하는 것임으로 const, let, var 모두 호이스팅이 발생한다.
그러면 왜 호이스팅이 일어나지 않는 것 처럼 보이는걸까?
이는 const와 let의 값 할당 시점이 var와 다르기 떄문이다.
일반적으로 변수는 다음과 같이 실행된다.
변수 선언 > 변수 초기화 > 변수 값 할당
var의 경우는 변수의 선언과 초기화가 동시에 일어난다. 이말인 즉 변수가 초기화가 되는데 할당이 되기 이전의 상태로 undefiend상태로 존재하게 된다.
그러나 let과 const는 변수의 선언과 초기화가 동시에 일어나지 않는다. 변수의 선언만 인정되어 실행컨택스트에는 담기게 되나(호이스팅이 일어난다.) 초기화가 되지 않았기 때문에 초기화 되기 이전에 console로 실행시키게 되면 error가 발생하게 된다.