JavaScript Hoisting


자바스크립트에서 호이스팅(Hoisting)은 변수, 함수 선언이 해당 스코프의 최상단으로 끌어올려진 것처럼 동작하는 메커니즘입니다. 이는 자바스크립트가 실행되기 전에 변수와 함수 선언을 메모리에 먼저 할당하기 때문에 발생합니다. 호이스팅은 변수를 선언하기 전에 사용할 수 있게 해주는 것처럼 보이지만, 실제로는 선언만 끌어올려지고 초기화는 그렇지 않기 때문에 주의가 필요합니다.

1. 변수 호이스팅

1.1 var 변수 호이스팅

var로 선언된 변수는 호이스팅되며, 선언과 초기화가 분리되어 처리됩니다. 선언은 스코프의 최상단으로 끌어올려지지만, 초기화는 실제 코드에 도달했을 때 이루어집니다.

console.log(hoistedVar); // undefined
var hoistedVar = 'I am hoisted';
console.log(hoistedVar); // I am hoisted

위 코드에서 hoistedVar 선언은 스코프의 최상단으로 끌어올려지지만, 초기화는 var hoistedVar = 'I am hoisted'; 부분에서 이루어집니다. 따라서, 첫 번째 console.log에서는 undefined가 출력됩니다.

1.2 let과 const 변수 호이스팅

letconst로 선언된 변수도 호이스팅되지만, 초기화는 호이스팅되지 않습니다. letconst 변수는 “일시적 사각지대(TDZ, Temporal Dead Zone)”에 놓이게 되어, 선언 전에 접근하려고 하면 참조 에러가 발생합니다.

console.log(hoistedLet); // Uncaught ReferenceError: Cannot access 'hoistedLet' before initialization
let hoistedLet = 'I am hoisted with let';

console.log(hoistedConst); // Uncaught ReferenceError: Cannot access 'hoistedConst' before initialization
const hoistedConst = 'I am hoisted with const';

위 코드에서 hoistedLethoistedConst는 선언 전에 접근하려고 하면 참조 에러가 발생합니다. 이는 letconst 변수가 호이스팅되지만, 초기화가 이루어지기 전에 접근할 수 없기 때문입니다.

2. 함수 호이스팅

함수 선언은 변수 선언과 달리 전체가 호이스팅됩니다. 즉, 함수 선언 전체가 스코프의 최상단으로 끌어올려져서 함수 선언 전에 호출이 가능합니다.

hoistedFunction(); // I am a hoisted function

function hoistedFunction() {
  console.log('I am a hoisted function');
}

위 코드에서 hoistedFunction은 함수 선언 전에 호출할 수 있으며, 정상적으로 작동합니다.

2.1 함수 표현식의 호이스팅

함수 표현식은 변수 선언처럼 동작하여, 선언은 호이스팅되지만 초기화는 호이스팅되지 않습니다.

console.log(hoistedFunction); // undefined
hoistedFunction(); // Uncaught TypeError: hoistedFunction is not a function

var hoistedFunction = function() {
  console.log('I am not hoisted');
};

위 코드에서 hoistedFunction은 변수 선언처럼 호이스팅되지만, 초기화는 실제 코드에 도달했을 때 이루어집니다. 따라서, 함수 표현식을 선언하기 전에 호출하면 TypeError가 발생합니다.

3. 클래스 호이스팅

클래스는 letconst처럼 호이스팅되지만 초기화되기 전에는 접근할 수 없습니다.

const instance = new MyClass(); // ReferenceError: Cannot access 'MyClass' before initialization

class MyClass {
  constructor() {
    this.name = 'MyClass';
  }
}

위 코드에서 MyClass는 호이스팅되지만 초기화되기 전에는 사용할 수 없으므로 참조 에러가 발생합니다.

4. 호이스팅의 실제 예제

다음은 호이스팅이 실제로 어떻게 작동하는지를 보여주는 예제입니다.

console.log(a); // undefined
var a = 5;

function example() {
  console.log(b); // undefined
  var b = 10;

  if (true) {
    var c = 20;
    let d = 30;
  }

  console.log(c); // 20
  console.log(d); // ReferenceError: d is not defined
}

example();

위 코드에서 abvar로 선언되었기 때문에 호이스팅됩니다. 따라서 초기화 전에 접근하면 undefined가 출력됩니다. c는 블록 스코프와 상관없이 함수 스코프에 속하기 때문에 함수 내 어디서든 접근할 수 있습니다. 그러나 dlet으로 선언되었기 때문에 블록 스코프를 가지며, 블록 외부에서는 접근할 수 없습니다.

5. 호이스팅과 함수 표현식

함수 표현식은 변수 호이스팅의 규칙을 따릅니다. 따라서 함수 표현식으로 정의된 함수는 선언 전에 호출할 수 없습니다.

hoistedFunction(); // TypeError: hoistedFunction is not a function

var hoistedFunction = function() {
  console.log('I am a hoisted function expression');
};

위 코드에서 hoistedFunction은 변수로 호이스팅되지만, 함수로 초기화되기 전에 호출하려고 하면 TypeError가 발생합니다.

호이스팅은 자바스크립트의 중요한 특성이며, 이를 이해하면 코드의 동작 방식을 더 잘 예측하고 디버깅할 수 있습니다. 특히, letconst의 호이스팅 동작을 이해하면 변수 선언 및 초기화와 관련된 오류를 줄일 수 있습니다.


Leave a Reply

Your email address will not be published. Required fields are marked *