호이스팅(Hoisting)이란 함수 내의 변수 및 함수 선언을 각 유효 범위의 최상단으로 끌어 올려주는 JS의 독특한 특징이다.
실제로 코드가 끌어올려지는 것은 아니고, 자바스크립트 parser가 내부적으로 끌어올려서 처리한다.
컴파일 단계에서 코드 실행 전 함수와 변수 선언을 스캔하고, 모든 함수와 변수 선언들은 렉시컬 환경이라 불리는 자바스크립트 데이터 구조 내의 메모리에 추가된다.
console.log(a); // undefined
var a = "A"; // var 변수
/* 호이스팅 된 코드 */
var a;
console.log(a);
a = "A";
var a를 상단으로 호이스팅했기 때문에 변수 선언 전에 console.log로 출력을 해도 에러가 발생하지 않고, undefined 가 출력된다.
모든 선언(function, var, let, const, class)은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let 및 const 선언은 초기화되지 않은 Temporal Dead Zone 상태로 유지된다.
자바스크립트에서는 총 3단계에 걸쳐서 변수를 생성한다.
myValue = undefined
myValue = 150
// 선언
lexicalEnvironment = {
a: <uninitialized>
}
// 초기화
lexicalEnvironment = {
a: undefined
}
// 할당
lexicalEnvironment = {
a: 10
}
var
는 선언과 동시에 초기화가 이루어진다. 즉, 선언과 동시에 undefined가 할당된다.
그러나 let
과 const
는 다르다. 선언만 될뿐, 초기화가 이루어지지 않는 메모리 할당이 아직 되지 않은 TDZ에 들어가게 된다.
모든 선언(function, var, let, const 및 class)은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let 및 const 선언은 초기화되지 않은 상태로 유지된다.
console.log(hoist); // Output: undefined
var hoist = 'The variable has been hoisted.';
console.log(hoist); // Output: ReferenceError: hoist is not defined ...
let hoist = 'The variable has been hoisted.';
var hoist = "AA";
(function func() {
console.log(hoist); // Output: ReferenceError
let hoist = "BB";
})();
만약 let과 const가 호이스팅이 되지 않는다면 console.log(hoist)
에 'AA' 가 출력되어야 하는데 ReferenceError 가 발생한다. 즉 let과 const도 호이스팅된다.
함수 선언식은 호이스팅 된다.
hoisted(); // Output: "This function has been hoisted."
function hoisted() {
console.log('This function has been hoisted.');
};
함수 표현식은 호이스팅 되지 않는다.
expression(); //Output: "TypeError: expression is not a function
var expression = function() {
console.log('Will this work?');
};
함수 표현식과 함수 선언식을 조합하여도 마찬가지로 호이스팅 되지 않는다.
expression(); // Ouput: TypeError: expression is not a function
var expression = function hoisting() {
console.log('Will this work?');
};
자바스크립트의 class 선언식은 호이스팅이 되고, 초기화하지 않은 'TDZ' 상태로 유지된다. 따라서 class에 접근하기 위해서는, 먼저 선언을 해야만한다.
var Frodo = new Hobbit();
Frodo.height = 100;
console.log(Frodo); // Output: ReferenceError: Hobbit is not defined
class Hobbit {
constructor(height) {
this.height = height;
}
}
함수 표현식처럼, class 표현식은 호이스팅되지 않는다.
var Square = new Polygon();
Square.height = 10;
console.log(Square); // Output: TypeError: Polygon is not a constructor
var Polygon = class Polygon {
constructor(height) {
this.height = height;
}
};
호이스팅은 함수를 어디에 선언 하였든지, 신경 쓰지 않고 필요한 곳에서 자유롭게 사용하기 위해 만들어진 기능이다. 그러나 이 기능이 때로는 의도치 않은 버그를 생성할 여지가 있다. 따라서 호이스팅을 의도적으로 사용하는 경우가 아니라면 호이스팅이 되지 않거나, Temporal Dead Zone 으로 초기화 되는 let, const, 함수 표현식을 사용하는 것을 권장한다.