변수와 함수의 선언을 해당 스코프의 최상단으로 끌어올리는 자바스크립트의 동작 방식
자바스크립트에서 변수가 "만들어지는" 과정은 사실 하나가 아니라 세 단계로 나뉜다. 이 세 가지를 혼동하면 호이스팅의 동작을 정확히 이해하기 어렵다.
| 단계 | 의미 | 예시 |
|---|---|---|
| 선언(Declaration) | 변수 이름을 메모리(스코프)에 등록하는 것 | var a, let a, const a |
| 초기화(Initialization) | 변수에 메모리 공간을 할당하고 기본값을 부여하는 것 | var는 undefined로 자동 초기화 |
| 할당(Assignment) | 변수에 실제 값을 넣는 것 | a = 1 |
비유하자면 이렇다. 선언은 빈 서랍에 이름표를 붙이는 것이고, 초기화는 그 서랍을 열어 '비어있음' 상태로 준비하는 것, 할당은 서랍 안에 물건을 넣는 것이다.
호이스팅은 이 중 "선언" 단계를 스코프 최상단으로 끌어올리는 동작이다. 단, var와 let/const는 초기화 시점이 다르기 때문에 전혀 다른 동작을 보인다.
var로 선언된 변수는 호이스팅 시점에 선언 + 초기화(undefined) 가 함께 이루어진다. 그래서 실제 할당 코드보다 앞에서 접근해도 에러가 나지 않고 undefined를 반환한다.
console.log(a); // undefined (선언+초기화는 됐지만, 아직 할당 전)
var a = 1;
console.log(a); // 1 (할당 완료)
자바스크립트 엔진이 실제로 해석하는 방식은 아래와 같다.
var a; // 선언 + 초기화(undefined) → 최상단으로 호이스팅
console.log(a); // undefined
a = 1; // 할당은 원래 위치에서 실행
console.log(a); // 1
또한 var는 함수 스코프만 인정한다. if, for와 같은 블록 {}은 스코프로 취급하지 않아서, 블록 안에서 선언한 var가 바깥으로 새어나오는 문제가 생긴다.
if (true) {
var x = 10;
}
console.log(x); // 10 — 블록 밖에서도 접근 가능 (의도치 않은 전역 오염)
let은 호이스팅이 되긴 하지만, 초기화는 실제 선언문에 도달하기 전까지 일어나지 않는다. 그래서 선언 전에 접근하면 ReferenceError가 발생한다.