hoisting이란, 변수가 선언되기 이전 코드에서 변수를 사용할 수 있는 현상을 말한다.
흔히 “변수가 스코프 최상단으로 끌어올려지는 현상” 이라고 하지만, 실제로는 변수를 끌어올리는 것이 아니라, 코드가 실행되기 전, 실행 컨텍스트의 생성 단계에서 모든 변수 선언을 변수 환경 객체에 프로퍼티로 저장하는 것이다.
hoisting은 변수 타입별로 다르게 적용된다.
| hoisting | 변수 환경 객체에 저장되는 초기값 | scope | |
|---|---|---|---|
| 함수 선언식 | ✅ | 실제 함수 | strict mode시 블록 스코프 |
| var 변수 | ✅ | undefined | 함수 스코프 |
| let, const 변수 | ❌ | <uninitialized>, TDZ | 블록 스코프 |
| 함수 표현식 & 화살표 함수 | ✅ / ❌ |
var 변수는 hoisting 되지만, 변수 환경 객체에 저장 될 때 undefined로 저장된다. 따라서 변수 선언 이전에 사용하려고 하면 undefined를 얻게 된다.var 변수를 선언 이전에 사용했을 때 에러도 아니고, 실제 할당된 값도 아닌 undefined 를 얻는건 과거 자바스크립트의 주된 버그 원인 중 하나였다. 모던 자바스크립트 문법에서는 let, const 등의 변수타입을 사용하고 var 사용을 거의 하지 않는 이유다. let, const 변수는 기술적으로는 hoisting 되지만, 저장되는 초기값이 <uninitialized>로, 실제적으로는 hoisting 되지 않는 듯한 효과가 난다. 이렇게 초기값이 <uninitialized>인 변수들은 TDZ(Temporal Dead Zone)을 가진다. TDZ는 **변수가 속한 스코프 영역의 시작부터 변수가 선언되기 전의 스코프 영역을 가리키는 말로, TDZ**에서 해당 변수를 사용하려고 하면 에러가 발생한다.let, const 변수를 TDZ에 사용할 경우 발생하는 에러const myName = 'Sunny';
if(myName === 'Sunny'){
console.log(`Sunny is a ${job}`);
// -> ReferenceError: Cannot access 'job' before initialization
const age = 2024 - 1994;
console.log(age);
const job = 'developer';
} 선언된 적이 없는 변수에 접근할 경우 발생하는 에러const myName = 'Sunny';
if(myName === 'Sunny'){
const age = 2024 - 1994;
console.log(age);
console.log(x);
// -> ReferenceError: x is not defined
} var 변수에 할당하면 undefined로 hoisting 될 것이고, let, const 변수에 할당하면 초기값이 <unintialized> 라서 선언 이전에 사용하면 에러가 발생하게 된다.