자바스크립트(JavaScript) - 호이스팅(Hoisting)

호이스팅의 정의

호이스팅이란 코드가 실행되기 전 변수선언/함수선언이 해당 스코프의 최상단으로 끌어올려진 것 같은 현상을 말한다. 자바스크립트 엔진은 코드를 실행하기 전에 실행 가능한 코드를 형상화하고 구분하는 과정을 거치는데, 이 때 모든 선언(var, let, const 등)을 스코프에 등록한다. 그래서 변수선언과 함수선언이 이미 저장되어 있기 때문에 선언문보다 참조나 호출이 나와도 오류 없이 동작할 수 있게 된다.

변수 호이스팅

자바스크립트의 모든 선언에는 호이스팅이 일어난다. 하지만 let, const, class등의 선언문들은 호이스팅이 발생하지 않은 것처럼 동작하는데, 실제로 let 선언문 이전에 변수를 참조하게 되면 레퍼런스 에러(참조 에러)가 발생하는데, 이는 let 키워드로 선언된 변수가 스코프의 시작에서 변수의 선언까지 일시적 사각지대(Temporal Dead Zone, TDZ)에 빠지게 되기 때문이다.

그렇다면 호이스팅의 정의는 틀린 것 아닌가요? 선언문 이전에 변수를 참조했을 때 에러가 나오게되면 문제가 있는 것 아닌가요?

하지만 실제로 자바스크립트 엔진에서, 모든 변수와 함수들의 선언은 먼저 메모리에 저장된다. 즉 ‘먼저 선언이 끌어올려진다’는 의미와 같고, 그렇기에 이 정의는 ‘참’이 된다.

var 선언문은 참조 에러 없이 동작하게되는데, 그 이유는 변수의 초기화다. var 키워드는 선언과 함께 undefined로 초기화되어 메모리에 저장하게 된다. 그러나 let, const등은 초기화되지 않은 상태로 선언만 메모리에 저장되기 때문에 초기화 되지 않은 변수를 참조하게 되어 참조 에러(초기화 되지 않으면 변수를 참조할 수 없음)가 나오게 되는 것이다. 그리고 이것은 선언들이 먼저 메모리에 저장된 호이스팅때문에 에러가 나오게 된다! 라고도 이해할 수 있다.

변수의 생성과정

변수는 총 3단계에 걸쳐서 생성된다.

1단계 : 선언 단계(Declaration Phase)

선언단계에서는 변수를 실행 컨텍스트의 변수 객체에 등록한다. 그리고 이 변수객체는 스코프가 참조하는 대상이 된다.

2단계 : 초기화 단계(Initialization Phase)

초기화 단계에서는 변수 객체에 등록된 변수를 위한 메모리 공간을 확보한다. 이 단계에서 변수는 undefined로 초기화하게 된다.

3단계 : 할당 단계(Assignment Phase)

undefined로 초기화 된 변수에 실제 값을 할당한다.

이 때 1단계인 선언 단계에서 호이스팅이 이루어지는 걸 알 수 있다. 다만 var 키워드의 경우에는 선언과 초기화를 동시에 하게 된다. 스코프에 변수를 등록하고 메모리에 그 공간을 확보하고 undefined로 초기화하기 때문에 에러가 발생하지 않는다.

let 키워드의 경우에는 선언과 초기화가 따로 하게 되기 때문에 스코프에 변수를 등록했지만 초기화 단계를 거치지 못했기 때문에 참조 에러가 발생하게 된다. 이 때 스코프의 시작 지점부터 초기화 시작 지점까지의 구간은 위에 언급한 일시적 사각지대(Temporal Dead Zone, TDZ)가 된다.

댓글남기기