[JavaScript] 끌어올려지는 선언. 호이스팅(Hoisting)의 모든 것

JavaScript 코드를 작성하다 보면 변수나 함수를 선언하기 전에 사용했는데도 에러 없이 동작하는 경우를 마주칠 수 있습니다. 이는 JavaScript 엔진이 코드를 실행하기 전, 변수 및 함수 선언을 해당 스코프의 최상단으로 끌어올리는 것처럼 동작하기 때문이며, 이러한 현상을 **호이스팅(Hoisting)**이라고 부릅니다. 호이스팅은 JavaScript의 독특한 특징으로, 이를 정확히 이해하지 못하면 코드의 동작을 예측하기 어려울 수 있습니다.

1. var 변수와 함수 선언의 호이스팅

전통적인 var 키워드와 함수 선언문은 호이스팅이 가장 명확하게 나타나는 대상입니다.

  • var 변수 호이스팅: var로 선언된 변수는 선언부만 스코프 최상단으로 끌어올려지며, undefined로 초기화됩니다. 할당문은 원래 위치에 그대로 남습니다.
console.log(myVar); // undefined (에러가 발생하지 않음)
var myVar = 10;
console.log(myVar); // 10

// 위 코드는 엔진에 의해 아래처럼 해석됩니다.
// var myVar;
// console.log(myVar);
// myVar = 10;
// console.log(myVar);
  • 함수 선언문 호이스팅: 함수 선언문은 함수 전체가 메모리에 올라가므로, 선언 위치와 상관없이 스코프 내 어디서든 호출할 수 있습니다.
sayHello(); // "Hello!"

function sayHello() {
  console.log("Hello!");
}

2. let, const와 TDZ (Temporal Dead Zone)

ES6에 도입된 letconst도 호이스팅이 발생하지만, var와는 다르게 동작합니다. 이들은 선언만 끌어올려지고 초기화는 되지 않습니다. 이로 인해 스코프의 시작 지점부터 변수 선언 지점까지 일시적으로 변수에 접근할 수 없는 구간이 생기는데, 이를 **일시적 사각지대(Temporal Dead Zone, TDZ)**라고 합니다.

  • TDZ 내에서 변수에 접근하려고 하면 ReferenceError가 발생합니다. 이는 undefined를 반환하는 var보다 훨씬 안전하고 예측 가능한 코드를 작성하게 해줍니다.
// console.log(myLet); // ReferenceError: Cannot access 'myLet' before initialization
let myLet = 20;
console.log(myLet); // 20

3. 함수 표현식의 호이스팅

함수 표현식(변수에 함수를 할당하는 방식)의 경우, 변수 선언 규칙에 따라 호이스팅이 적용됩니다. var로 할당했다면 변수 선언만 호이스팅되고 undefined를 가지므로, 할당 전에 함수로 호출하면 TypeError가 발생합니다.

// sayHi(); // TypeError: sayHi is not a function
var sayHi = function() {
  console.log("Hi!");
};

요약 및 정리

호이스팅은 JavaScript 엔진의 코드 처리 방식을 이해하는 데 중요한 개념입니다.

  • var와 함수 선언문: 선언이 스코프 최상단으로 끌어올려집니다. varundefined로 초기화, 함수 선언문은 전체가 호이스팅됩니다.
  • let, const: 선언만 호이스팅되며, TDZ로 인해 선언 전에 접근할 수 없어 코드의 안정성을 높입니다.
  • 권장 사항: 호이스팅으로 인한 혼란을 피하기 위해, 항상 스코프의 시작 부분에서 변수와 함수를 선언하는 습관을 들이는 것이 좋습니다. 또한, var 대신 letconst를 사용하면 TDZ 덕분에 잠재적인 버그를 쉽게 발견할 수 있습니다.