
console.log(foo); // undefined
var foo;
변수 선언문이 참조하는 코드보다 뒤에 있는데도, 참조 에러가 발생하는 것이 아니라 undefined가 출력된다.
자바스크립트 엔진은 코드를 실행하기 전에 실행 컨텍스트를 생성해 소스코드를 평가하고 실행하기 위한 준비를 한다. 이때 자바스크립트 엔진은 선언문(변수 선언문, 함수 선언문 등)을 먼저 실행하고, 평가 과정이 끝나고 나서야 선언문을 제외한 소스코드를 차례대로 실행한다. 이처럼 선언문이 스코프의 최상단으로 끌어 올려진 것처럼 동작하는 자바스크립트의 특징을 호이스팅이라고 부른다.
실행 컨텍스트에서 변수 선언은 2단계로 진행된다.
- 선언 단계: 변수를 등록한다. 실행 컨텍스트에 객체 형태로 등록된다.
- 초기화 단계: 값을 저장하기 위한 메모리 공간을 확보하고 undefined를 할당해 초기화한다.
값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 진행된다.
선언 단계와 초기화 단계를 동시에 진행한다. 따라서 var 키워드로 선언한 변수는 값을 할당하지 않았어도 undefined라는 값을 갖는다.
선언 단계 + 초기화 단계 👉 할당 단계
console.log(foo); // ReferenceError
let foo;
let 키워드를 사용해서 변수를 선언하고, 그보다 앞 줄에서 변수를 참조했을 때에는 undefined가 출력되는 것이 아니라 참조 에러가 발생한다. 그렇다면 let은 호이스팅 되지 않는 걸까?
var와 달리 let과 const는 선언 단계와 초기화 단계가 분리되어 있다. var와 마찬가지로 런타임 이전에 선언 단계가 먼저 실행되지만, 초기화 단계는 변수 선언문에 도달했을 때 실행된다. 그렇기 때문에 스코프의 시작 지점부터 초기화 단계 이전 까지는 메모리가 할당되지 않아 변수를 참조할 수 없다. 이 구간을 TDZ(Temporal Dead Zone), 일시적 사각지대라고 부른다.
let foo = 100;
{
console.log(foo); // ReferenceError
let foo = 200;
}
let이 호이스팅되지 않는다면 ReferenceError가 발생하는 것이 아니라, 전역 변수 foo의 값인 100이 출력되었을 것이다.
const 키워드로 변수를 선언할 때는 선언과 동시에 초기화를 해야 한다. 그렇기 때문에 호이스팅이 발생하지 않는 것처럼 보이지만, let과 마찬가지로 const도 호이스팅이 발생한다.
const foo; // SyntaxError
선언 단계 👉 TDZ 👉 초기화 단계 👉 할당 단계
let과 const는 ES6에서 var의 단점을 보완하기 위해 새롭게 추가되었다.
코드를 예측가능하게 만들고, 잠재적 버그를 쉽게 찾아낼 수 있도록 한다.
var 사용은 지양하고, 기본적으로 const를 사용하되 재할당이 필요한 경우에만 let을 활용하자!
이웅모, 『모던 자바스크립트 Deep Dive』, 위키북스
https://velog.io/@modolee/javascript-let-const-hoisting