호이스팅(hoisting)
이란 var 선언문이나 function 선언문 등을 해당 scope의 선두로 옮긴 것처럼 동작하는 특성을 말한다.
자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, class)을 호이스팅한다.
📌우선 변수가 생성되는 과정을 자세히 살펴보자.
선언 단계(Declaration phase)
초기화 단계(Initialization phase)
할당 단계(Assignment phase)
🌼 var
키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
// scope의 선두에서 선언 단계와 초기화 단계가 실행된다.
console.log(foo); // undefined
var foo; // 변수 선언문
console.log(foo); // undefined
foo = 1; // 할당문 : 할당 단계
console.log(foo); // 1
👉 var은 scope에 변수를 등록(선언 단계)하고 메모리에 변수를 위한 공간을 확보한 뒤, undefined로 초기화(초기화 단계)한다.
👉 변수 선언문 이전에 변수에 접근하여도 scope에 변수가 존재하기 때문에 에러가 발생하지 않는다. 이러한 현상을 '변수 호이스팅'이라 한다.
🌼 let
키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행된다.
// scope의 선두에서 선언 단계만 실행된다.
console.log(foo); // Uncaught ReferenceError: foo is not defined
let foo; // 변수 선언문 : 초기화 단계
console.log(foo); // undefined
foo = 1; // 할당문 : 할당 단계
console.log(foo); // 1
👉 let은 scope에 변수를 등록(선언 단계)하지만, 초기화 단계는 변수 선언문에 도달했을 때 이루어진다.
👉 초기화 이전에 변수에 접근하려고 하면 참조 에러(Reference Error)가 발생한다. 변수를 위한 메모리 공간이 아직 확보되지 않았기 때문이다.
👉 scope의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없으며, 해당 구간을 '일시적 사각지대(Temporal Dead Zone; TDZ)'라고 부른다.
📚 예제 1 ) 매개변수와 변수에 대한 호이스팅
function foo(x) {
console.log(x); // (1)
var x;
console.log(x); // (2)
var x = 2;
console.log(x); // (3)
}
foo(1);
이때 (1), (2), (3) 에서 어떤 값들이 출력될까?
우선, 함수를 호출하면서 '1'이라는 인자가 전달된 것을, 함수 내부에서 변수를 선언한 것과 같이 표현할 수 있다.
function foo() {
var x = 1;
console.log(x); // (1)
var x;
console.log(x); // (2)
var x = 2;
console.log(x); // (3)
}
foo();
이제, 선언문만 끌어올리고 할당문은 원래 자리에 남겨두면 다음과 같다.
function foo() {
var x;
var x;
var x;
x = 1;
console.log(x); // (1)
console.log(x); // (2)
x = 2;
console.log(x); // (3)
}
foo();
결과적으로, (1) 1, (2) 1, (3) 2 가 출력된다.
📚 예제 2 ) 함수 선언의 호이스팅
function foo() {
console.log(b); // (1)
var b = 'bbb';
console.log(b); // (2)
function b() {}
console.log(b); // (3)
}
foo();
이때 (1), (2), (3) 에서 어떤 값들이 출력될까?
선언문만 끌어올리고 할당문은 그대로 남겨두자.
function foo() {
var b;
function b() {};
console.log(b); // (1)
b = 'bbb';
console.log(b); // (2)
console.log(b); // (3)
}
foo();
이때, 함수 선언문은 함수명으로 선언한 변수에 함수를 할당한 것으로 볼 수 있다.
function foo() {
var b;
var b = function b() {};
console.log(b); // (1)
b = 'bbb';
console.log(b); // (2)
console.log(b); // (3)
}
foo();
결과적으로, (1) b 함수, (2) 'bbb', (3) 'bbb' 가 출력된다.
📚 예제 3 ) 함수 선언문과 함수 표현식의 호이스팅
console.log(sum(1, 2)); // (1)
console.log(multiply(3, 4)); // (2)
function sum(a, b) {
return a + b;
}
var multiply = function(a, b) {
return a * b;
}
이때 (1), (2) 에서 어떤 값들이 출력될까?
함수 선언문의 경우 전체가 hoisting되지만, 함수 표현식은 변수의 선언문만 hoisting된다.
var sum = function sum(a, b) {
return a + b;
}
var multiply; // 선언문
console.log(sum(1, 2)); // (1)
console.log(multiply(3, 4)); // (2)
multiply = function(a, b) { // 할당문
return a * b;
}
결과적으로, (1) 3, (2) 'multiply is not a function'이 출력된다.
출처 )
PoiemaWeb : block & scope
정재남(2019), [코어 자바스크립트], 위키북스