호이스팅의 정의
호이스팅이란 함수 안에 있는 선언들을 모두 끌어올려 해당 함수의 유효 범위 최상단에 선언하는 것을 의마합니다. 이는 함수 정의보다 호출을 먼저 하더라도 문제없이 작동하는 유용한 특성입니다.
실제 코드가 끌어올려지는 것은 아니고, JS parser 내부적으로 끌어올려 처리하는 것입니다. (따라서 실제 메모리에서 변화는 없습니다.)
호이스팅의 주의사항
코드의 가독성과 유지 보수를 위해 호이스팅이 일어나지 않도록 하는 것이 바람직합니다.
호이스팅을 제대로 모르더라도 함수와 변수를 가급적 코드 상단부에 미리 선언하면 호이스팅으로 인한 스코프 꼬임 현상 방지가 가능합니다.
자바크립트의 모든 선언에는 호이스팅이 일어납니다.
하지만, let / const / class 키워드를 이용한 선언문은 호이스팅이 발생하지 않은 것처럼 오류가 발생합니다. (글 하단 TDZ 참고)
일반함수와 익명함수는 호이스팅 동작이 서로 다릅니다.
function print() {
/* 함수 선언문 */
let result_1 = inner();
console.log(result_1); // == string inner
function inner() {
return 'inner';
}
//
/* 함수 표현식 */
let result_2 = callInner();
console.log(result_2); // TypeError: callInner is not a function
var callInner = function () {
return 'callInner';
};
//
}
print();
function calling() {
console.log('callFunc');
}
var calling = 'callInner';
console.log(typeof calling); // == string
//--------------JS Parser 내부 호이스팅 과정--------------//
// 1. 변수 선언
var calling;
// 2. 함수 선언
function calling() {
console.log('callFunc');
}
// 3. 변수값 할당
calling = 'callIndder';
var callingA; // 값 할당 X
var callingB = 'callingB'; // 값 할당 O
// 같은 이름의 함수들 선언
function callingA() {
console.log('callingA Func');
}
function callingB() {
console.log('callingB Func');
}
console.log(typeof callingA); // == function
console.log(typeof callingB); // == string
값이 할당되어 있지 않은 변수의 경우, 함수 선언문이 변수를 덮어씁니다. (= callingA)
값이 할당되어 있는 변수의 경우, 변수가 함수 선언문을 덮어 씁니다. (= callingB)
==> 예기치 못한 상황이 발생할 수 있습니다! var를 사용하지 않는 많은 이유 중 하나가 아닐까 ㅎ.ㅎ
TDZ란 선언 전에 변수를 사용한는 것을 비 허용하는 개념상의 공간입니다. 따라서 값을 할당하기 전에 해당 변수를 사용할 수 없도록 하여 잠재적인 버그를 줄일 수 있습니다.
let / const / class 구문은 TDZ의 영향을 받습니다. (var는 암묵적으로 undefined로 초기화된 상태로 JavaScript에서 읽기 때문에 영향을 받지 않음)
var / function / import 구문은 TDZ의 영향을 받지 않습니다.
/* TDZ */
console.log(call);
/* */
let call = 'call Func'; // 변수의 선언 및 할당