프론트엔드

호이스팅

2026. 03. 23. 월요일 오후 8시 17분

호이스팅에 대하여

이상한 avascript 문제

1sayHello(); // 정상 동작?
2
3function sayHello() {
4  console.log('hello');
5}
6

위의 코드를 보면, 선언보다 먼저 sayHello()를 호출합니다. 미리 스포하자면, 위의 코드는 정상동작합니다.

1sayHello();
2
3var sayHello = function () {
4  console.log('hello');
5};
6

마찬가지로 선언보다 먼저 호출한 경우인데, 이번에는 에러가 발생합니다.

둘 다 sayHello를 선언 전에 호출했는데, 왜 결과가 다를까요? 이 문제를 해결하려면, 호이스팅을 이해해야 합니다.

호이스팅(Hoisting)이란?

함수 및 변수 선언이 유효범위 최상단으로 끌어올려지는 현상을 호이스팅이라고 부릅니다.

실행 컨텍스트가 생성되면, JS는 코드를 실행하기 전에 먼저 변수 정보를 수집합니다. 이 때, var로 선언한 변수와 function으로 선언한 함수의 선언 및 정의 정보가 수집됩니다. 이러한 자바스크립트 엔진의 동작 때문에, sayHello 함수 정의가 호이스팅되어 정상적으로 호출할 수 있었던 것 입니다.

그렇다면, 왜 var sayHello = function() {...}은 에러가 발생한걸까요?

함수 선언식 vs 함수 표현식

그 이유는 함수 선언식과 표현식의 차이 때문입니다.

1sayWow(); // (3) → "wow" 출력
2sayYeah(); // (5) → TypeError 발생!
3
4var sayYeah = function () {
5  // (1) 선언, (6) 대입
6  console.log('yeah');
7};
8
9function sayWow() {
10  // (2) 선언과 동시에 정의(호이스팅)
11  console.log('wow'); // (4)
12}
13

실행 순서를 따라가 보면 이렇습니다.

  • 실행 컨텍스트가 생성될 때, sayYeah 변수는 선언만 수집됩니다. 값은 undefined입니다.
  • 반면 sayWow 함수는 선언과 정의가 동시에 수집됩니다.
  • 따라서 sayWow()는 선언 전에 호출해도 정상 동작하지만, sayYeah()는 대입 전에 호출하면 에러가 납니다.
구분호이스팅 시선언 전 호출
함수 선언식 function f() {}선언 + 정의 모두 수집✅ 가능
함수 표현식 var f = function() {}변수 선언만 수집 (값은 undefined)❌ 에러

정리하면, 함수 선언식은 선언과 정의가 동시에 수집되어, 해당 코드를 만나기 전에도 문제 없이 호출이 가능하지만, 함수 표현식은 변수 선언만 수집되므로 호출할 수 없습니다.


let/const와 TDZ

그렇다면 var을 사용한 선언만 호이스팅되는걸까요? var만 호이스팅된다고 오해하기 쉽지만, letconst도 호이스팅이 일어납니다. 하지만 큰 차이가 있습니다.

1console.log(a); // undefined
2console.log(b); // ReferenceError: Cannot access 'b' before initialization
3
4var a = 1;
5let b = 2;
6
  • var는 선언과 동시에 undefined로 초기화됩니다.
  • let/const는 선언은 수집되지만, 초기화는 코드상 선언부에 도달해야 이루어집니다.

선언부에 도달하기 전까지의 구간을 TDZ(Temporal Dead Zone, 일시적 사각지대) 라고 부릅니다. 이 구간에서 변수에 접근하면 ReferenceError가 발생합니다.

1// TDZ 시작
2console.log(x); // ReferenceError
3
4let x = 10; // 이 줄에서 TDZ 종료, 초기화 완료
5// TDZ 종료
6
구분호이스팅초기화 시점선언 전 접근
var호이스팅 시 undefined⚠️ undefined 반환
let선언부 도달 시❌ ReferenceError
const선언부 도달 시❌ ReferenceError

정리

  • 함수 선언식은 선언과 정의가 함께 호이스팅되어 선언 전 호출이 가능합니다.
  • 함수 표현식과 var는 선언만 호이스팅되고, 값은 undefined입니다.
  • let/const는 호이스팅이 일어나지만 TDZ로 인해 선언 전 접근 시 에러가 발생합니다.

var보다 let/const를 권장하는 이유 중 하나가 바로 이 차이입니다. var는 선언 전에 접근해도 undefined를 반환하기 때문에 개발자가 자신의 실수를 알아차리기 어려울 수 있습니다. 반면 let/const는 TDZ 덕분에 선언 전 접근 시 즉각 ReferenceError를 던집니다. 덕분에 바로 알아차릴 수 있습니다.

마치며

솔직히 요새는 var을 거의 사용하지 않기 때문에, 실무에 크게 도움이 되는 내용은 아닙니다. ☺️ 하지만 이 매커니즘을 알면 스코프 체인, this 바인딩 같은 심화 개념을 배울 때 수월하게 이해할 수 있어서 다루어보았습니다. 또 혹시 모릅니다. 레거시 코드를 뜯어봐야할 때 도움이 될지도 모릅니다. 😩 긴 글 읽어주셔서 감사합니다.