// 1번 코드
a = 2;
var a;
console.log(a); // ?
위의 코드를 실행하면 어떤 결과가 나올까?
var a 선언으로 인해 해당 변수가 재정의되어 기본값인 undefined가 출력될 것이라고 예상하겠지만, 이 코드의 실행 결과는 2이다.
// 2번 코드
console.log(a); // ?
var a = 2;
위의 코드 출력 결과는 2나 ReferenceError가 아닌, undefined이다.
이러한 동작을 살펴보기 위해선 3단계에 거친 변수의 생성 과정에 대해 살펴볼 필요성이 있다.
1) 선언 단계 (Declaration Phase)
2) 초기화 단계 (Initialization Phase)
3) 할당 단계 (Assignment Phase)
위의 예제와 같이 var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
이러한 현상을 변수 호이스팅(Variable Hoisting)이라 한다.
함수에서도 마찬가지로 호이스팅이 발생한다.
함수 foo의 선언문은 호이스팅되었기 때문에 첫째 줄에서 foo를 호출할 수 있다. 이때, 호이스팅이 스코프별로 작동한다.
foo();
function foo() {
console.log(a); // undefined
var a = 2;
}
// 위 코드의 실제 동작
function foo() {
var a;
console.log(a);
a = 2;
}
foo();
함수 선언문은 이와 같이 호이스팅되지만, 함수 표현식은 다르다.
foo(); // TypeError : foo is not a function
var foo = () => {
console.log(a);
var a = 2;
}
변수 식별자 foo는 호이스팅되어 글로벌 스코프에 묶이므로 foo() 호출은 실패하지 않고, ReferenceError도 발생하지 않는다. 그러나 foo는 아직 값을 갖고 있지 않은데 반해, foo()가 undefined 값을 호출하려해 TypeError라는 에러를 발생시킨다.
📌 함수와 변수 선언문은 모두 호이스팅되지만, 함수 선언문이 먼저 호이스팅되고 다음으로 변수 선언문이 호이스팅된다는 특징이 있다.
foo(); // 1
var foo;
function foo() {
console.log(1);
}
foo = () => {
console.log(2);
}
자바스크립트 엔진은 위의 코드를 다음과 같이 해석한다.
function foo() {
console.log(1);
}
foo();
foo = () => {
console.log(2);
}
참고 : Hoisting – 용어 사전 | MDN
참고 : let, const | PoiemaWeb