변수와 함수의 선언을 해당 스코프의 최상단으로 끌어올리는 자바스크립트의 동작 방식

1. 선언 / 초기화 / 할당, 세 가지를 먼저 구분하자


자바스크립트에서 변수가 "만들어지는" 과정은 사실 하나가 아니라 세 단계로 나뉜다. 이 세 가지를 혼동하면 호이스팅의 동작을 정확히 이해하기 어렵다.

단계 의미 예시
선언(Declaration) 변수 이름을 메모리(스코프)에 등록하는 것 var a, let a, const a
초기화(Initialization) 변수에 메모리 공간을 할당하고 기본값을 부여하는 것 varundefined로 자동 초기화
할당(Assignment) 변수에 실제 값을 넣는 것 a = 1

비유하자면 이렇다. 선언은 빈 서랍에 이름표를 붙이는 것이고, 초기화는 그 서랍을 열어 '비어있음' 상태로 준비하는 것, 할당은 서랍 안에 물건을 넣는 것이다.

호이스팅은 이 중 "선언" 단계를 스코프 최상단으로 끌어올리는 동작이다. 단, varlet/const는 초기화 시점이 다르기 때문에 전혀 다른 동작을 보인다.

2. var, let, const — 호이스팅 동작 비교


2-1) var — 선언과 초기화가 동시에 호이스팅된다

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 — 블록 밖에서도 접근 가능 (의도치 않은 전역 오염)

2-2) let — 선언만 호이스팅되고, 초기화는 선언 코드에 도달해야 일어난다

let은 호이스팅이 되긴 하지만, 초기화는 실제 선언문에 도달하기 전까지 일어나지 않는다. 그래서 선언 전에 접근하면 ReferenceError가 발생한다.