[ECMAScript] 호이스팅(Hoisting)

Featured image

JavaScript에서 호이스팅(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.

즉, 변수나 함수 선언을 함수 스코프의 맨 위로 이동하는 것을 말한다.

변수 호이스팅

변수는 아래와 같이 3단계에 걸쳐 생성된다.

  1. 선언 - 변수를 선언하여 실행 컨텍스트의 변수 객체에 등록한다.
  2. 초기화 - 변수 객체에 대한 메모리를 할당하고, 변수는 undefined 로 초기화 된다.
  3. 할당 - 초기화된 변수에 실제 값을 할당한다.

var은 변수의 선언과 초기화가 동시에 일어난다. 따라서 선언문 이전에 해당 변수에 접근하여도 호이스팅에 의하여 에러가 발생하지 않고, undefined 를 반환한다. 이를 변수 호이스팅(Variable Hoisting) 이라고 한다.

console.log(foo); // undefined

var foo;
console.log(foo); // undefined

foo = 1;
console.log(foo); // 1

let 은 var 과 달리 선언과 초기화가 분리되어 발생한다. 즉, 스코프에 변수를 선언하지만 초기화는 변수의 선언문에 도달했을 때 이루어진다. 그렇기 때문에 초기화 이전에 변수에 접근한다면 참조 에러가 발생하게 된다. 즉, 스코프의 시작 지점부터 변수 초기화 시작 지점까지는 변수를 참조할 수 없게 되는데, 이를 일시적 사각지대(TDZ) 라고 한다.

function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError
  var bar = 1;
  let foo = 2;
}

함수 호이스팅

함수는 선언식, 표현식에 따라 호이스팅에 의한 결과가 달라진다.

함수 선언식

printName(); // minjung

function printName() {
  console.log('minjung');
}

함수 선언식의 경우 호이스팅이 발생하여 함수를 최상단으로 끌어올려 printName 함수를 먼저 호출 하더라도 정상적인 결과를 출력한다.

함수 표현식

printName(); // Uncaught TypeError: printName is not a function

var printName = function() {
  console.log('minjung');
}

함수 표현식의 경우 호이스팅에 의하여 var printName 은 선언과 초기화가 발생하고 할당이 되므로 아래의 코드처럼 된다.

var printName; // undefined

printName(); // Uncaught TypeError: printName is not a function

printName = function() {
  console.log('minjung');
}

그러므로 printName은 호이스팅 선언과 초기화로 인해 undefined 값이 반환되므로 함수가 아니라는 오류 메세지가 발생하게 된다.

(let 으로 선언한 함수 표현식의 경우에는 변수 선언때와 동일하게 정의되지 않은 값이라는 ReferenceError 가 발생한다.)


Reference