호이스팅이란?
자바스크립트 엔진이 소스코드를 실행하기 전 소스코드 평가과정에서 변수 선언을 포함한 모든 선언문을 실행하는 과정.
console.log(a); // ?
var a = 1;
위 코드에서 변수 a가 선언되기 전에 a를 참조하면 어떤일이 발생할까?
정답은 undefined가 출력된다.
그 이유는 변수 선언문과 함수 선언문은 코드가 실행되기 전 즉 런타임 이전에 먼저 실행되기 때문이다. 이처럼 선언문이 코드의 최상단으로 끌어올려진 것처럼 동작하는 자바스크립트 고유의 특징을 호이스팅(hoisting)이라 불린다.
var a = 1;
변수를 선언할때 선언문을 이렇게 작성하더라도 자바스크립트 엔진은 다르게 동작한다.
var a;
a = 1
이처럼 var a로 a라는 변수가 선언되고 a에 1이 할당되는 모습이다. 하지만 var a가 선언되고 선언과 동시에 undefined로 초기화되는 한가지 과정이 더 있다.
자바스크립트 엔진의 변수 선언 과정
- 선언단계 : 코드 평가단계에서 변수 이름을 실행 컨텍스트에 등록
- 초기화단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당
여기서 초기화단계를 거치는 이유는 확보된 메모리공간에 다른 애플리케이션이 사용했던 값이 남아 있을 수 있고 undefined로 할당하지 않고 변수 값을 참조하면 쓰레기 값이 나올 수 있다. 이러한 위험을 막기위해 자바스크립트 엔진은 초기화단계를 거치는 것이다.
이후 코드 실행과정에서 선언문을 만나면 a에 1이 할당된다.
여기서 주의할 점은 변수에 값을 할당할때 이전 값인 undefined가 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당 값 1을 저장하는 것이 아니라 새로운 메모리 공간을 확보하고 그곳에 1을 저장한다.
console.log(b); // ReferenceError
let b = 1
let, const는 호이스팅이 발생하지 않는 것 처럼 동작한다.
var 키워드는 선언단계와 초기화단계가 한번에 진행되지만 let, const 키워드는 선언단계와 초기화단계가 분리되어 진행된다.
먼저 코드 평가단계에서 let, const 키워드로 선언된 변수는 실행컨텍스트에 등록된다. 이 과정에서 변수가 메모리에 등록되어있지않아 스코프 시작지점부터 변수 선언문직전사이에 참조하면 값을 읽어올 수 없어 ReferenceError가 발생한다. 이 구간을 TDZ(Temporal Dead Zone)이라고 부른다.
ReferenceError
: 값을 참조하려 했지만 자바스크립트 엔진이 등록된 식별자를 찾을 수 없을때 발생하는 에러
함수 호이스팅
함수 선언문은 함수 자체가 호이스팅되어 함수 선언문 전에도 참조할 수 있지만 함수 표현식은 변수에 할당되기 때문에 변수 호이스팅과 동일하게 동작한다.
참고 - 모던 자바스크립트 Deep Dive