변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 호이스팅이라고 한다.
var, let, const, function, class 키워드를 사용해서 선언하는 모든 식별자는 호이스팅이 된다.
console.log(score); // undefined
var score;
변수 선언문보다 변수를 참조하는 코드가 앞에 있어 ReferenceError가 발생해야 하지만 undefined가 출력된다. 이는 변수 선언(선언+초기화)이 소스코드가 실행되는 런타임 이전에 먼저 실행된다는 증거이다.
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError : Cannot acess 'foo' before initailization
let foo = 2; // 지역 변수
}
const Person = '';
{
console.log(Person);
// ReferenceError : Cannot acess 'Person' before initailization
class Person {}
}
let 키워드는 선언 단계와 초기화 단계가 분리되어 진행된다. 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다. (const 키워드는 선언 단계와 초기화 단계가 동시에 진행된다.)
let, const, class가 호이스팅이 발생하지 않는 거 처럼 느껴지는 이유는 일시적 사각지대 때문이다.
초기화 단계 시작 지점까지 변수를 참조할 수 없으며, 초기화 단계가 실행되기 이전에 변수에 접근하려고 하면 참조 에러가 발생한다. 이를 일시적 사각지대라고 부른다.
console.dir(add); // add(x,y)
console.dir(sub); // undefined
console.log(add(2,5)); // 7
console.log(sub(2,5)); // TypeError: sub is not a function
// 함수 선언문
function add(x, y){
return x+y;
}
// 함수 표현식
var sub = function (x, y){
return x - y;
}
함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있다. 하지만 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다. 둘의 함수 생성 시점이 다르기 때문이다.
함수 선언문 이전에 호출하면, 암묵적으로 생성된 식별자는 함수 객체로 초기화된다.
함수 표현식은 변수에 할당되는 값이 함수 리터럴인 문이다. 변수 할당문의 값은 할당문이 실행되는 시점, 즉 런타임에 평가되므로 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다.
따라서 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생한다.

따라서 함수 표현식 이전에 함수를 참조하면 undefined로 평가된다. 이때 함수를 호출하면 undefined를 호출하는 것과 마찬가지이다. 함수 표현식으로 정의한 함수는 반드시 함수 표현식 이후에 참조 또는 호출해야 한다.