JavaScript의 Hoisting
코드 실행 전 실행 컨텍스트를 생성하는 과정에서 변수, 함수, 클래스의 선언 정보를 수집합니다.
자바스크립트 인터프리터는 전역공간, eval()
함수, 함수 등을 실행하기 전 실행할 코드에 관한 환경 정보를 모은 객체를 생성합니다. 이 객체를 실행 컨텍스트라고 부르는데, 실행 컨텍스트를 생성하는 과정에서 변수, 함수, 클래스의 선언 정보를 수집합니다(단, 값 할당 정보는 수집하지 않습니다). 실행 컨텍스트는 실제 코드가 실행되기 전에 생성되므로 자바스크립트 인터프리터는 코드를 실행할 때 이미 해당 스코프의 모든 변수, 함수, 클래스의 선언 정보를 가지고 있는 상태가 됩니다. 이로 따라 아래와 같은 현상이 발생하게 되며 이러한 현상을 ‘Hoisting(호이스팅)’이라고 부릅니다.
- 변수 선언 코드보다 앞선 코드에서 해당 변수의 값을 사용할 수 있습니다.
- 변수 선언 코드보다 앞선 코드에서 해당 변수를
ReferenceError
없이 참조할 수 있습니다. 이때undefined
값을 반환합니다. (단,const
,let
을 이용한 선언일 경우ReferenceError
가 발생합니다) - 변수 선언 코드가 자신보다 앞선 코드에 영향을 줄 수 있습니다.
변수 선언 코드보다 앞서 변수값 사용
a();
function a() {}; // -> (1)
- 함수 선언이 있으므로 코드 실행에 앞서 수집합니다. 단, 함수는 선언과 함께 함수 내용이 함께 수집됩니다. 전역공간 실행 컨텍스트에 함수
a
가 추가되었습니다. - 코드 실행 - 실행 컨텍스트에 존재하는 함수
a
를 정상적으로 호출합니다.
function a() {
console.log(b); // ƒ b() {}
var b = 1; // -> (1)
console.log(b); // 1
function b() {}; // -> (2)
console.log(b); // 1
}
a();
- (1) - 변수 선언이 있으므로 코드 실행에 앞서 수집합니다. 함수
a
실행 컨텍스트에 변수b
가 추가되었습니다. - (2) - 함수 선언이 있으므로 코드 실행에 앞서 수집합니다. 함수
a
실행 컨텍스트에 이미 변수b
가 있으므로 이를 덮어씁니다. 이제 변수b
의 값은 함수b
입니다. - 코드 실행 - 첫 번째
console.log(b)
실행 시 실행 컨텍스트에 변수b
가 존재하므로 그 값인function b() {}
가 출력됩니다. 이후 값1
할당 코드가 실행된 이후부터는1
이 출력됩니다.
변수 선언 코드보다 앞서 변수 참조
console.log(a); // Uncaught ReferenceError: a is not defined
console.log(b); // undefined
var b = 1; // (1)
- (1) - 변수 선언이 있으므로 코드 실행에 앞서 수집합니다. 전역공간 실행 컨텍스트에 변수
b
가 추가되었습니다. - 코드 실행 - 변수
a
는 존재하지 않으므로ReferenceError
가 발생하지만 변수b
는 비록 값은 할당되지 않았지만 수집된 선언 정보가 있으므로 이를 참조하여undefined
를 반환합니다.
변수 선언 코드보다 앞선 코드에 영향
const x = 1; // -> (1)
{
console.log(x); // ReferenceError
const x = 2; // -> (2)
}
- (1) - 상수 선언이 있으므로 코드 실행에 앞서 수집합니다. 전역공간 실행 컨텍스트에 상수
x
가 추가되었습니다. - (2) - 상수 선언이 있으므로 코드 실행에 앞서 수집합니다. 블럭 실행 컨텍스트에 상수
x
가 추가되었습니다. - 코드 실행 - 전역공간에 상수
x
가 존재하지만 자신의 스코프인 블럭 실행 컨텍스트에 상수x
가 있으므로 이를 우선 참조합니다. 아직 선언된 값이 없고,const
로 선언되었으므로ReferenceError
가 발생합니다. 만약(2)
코드가 없었다면 전역공간에 선언된 상수x
값을 참조하였을 것입니다. 코드(2)
는 자신보다 앞선 코드인console.log(x)
실행에 영향을 주었습니다.