호이스팅은 간단히 말해 변수나 함수, 클래스 또는 임포트(import)의 선언문을을 코드 맨 위로 끌어올리는 것처럼 동작하는 매커니즘이다.
하지만 실제로 코드가 물리적으로 이동하는 건 아니고, 자바스크립트 엔진이 실행 전에 코드를 스캔하면서 변수와 함수 선언을 미리 처리하여 메모리에 등록한다.

선언만 맨 위로 올라가고, 값은 undefined로 초기화
console.log(x1); // undefined => x1 변수가 hoisting되어 선언된 것으로 처리
var x1;
console.log(x1); // undefined
console.log(x2); // undefined
var x2 = 100;
console.log(x2); // 100
내부적으로 아래와 같이 해석되어 실행
var x1;
console.log(x1); // undefined
console.log(x1); // undefined
var x2;
console.log(x2); // undefined
x2 = 100;
console.log(x2); // 100
선언만 올라가지만 초기화되지 않아서 사용하려면 ReferenceError 에러 발생

❗️하지만 ReferenceError 에러가 발생했다고 호이스팅이 되지 않았다고 생각하면 안된다.
let과 const는 호이스팅 되어 변수를 메모리에 올려두었지만, 초기화 되지 않은 상태로 일시적 사각지대(TDZ, Temporal Dead Zone)에 머물러 있어 선언한 코드 줄을 지나야 접근 가능한 상태이다.
TDZ란?
쉽게 말해서 선언만 되고 아직 초기화 되지 않는 변수가 머무는 공간
console.log(x3); // Cannot access 'x3' before initialization
let x3 = 100;
console.log(x3); // 100
내부적으로 아래와 같이 해석되어 실행
let x3; // 변수 선언이 호이스팅되지만 초기화되지 않음
// ⇒ TDZ 본관 ⇒ 초기화되기 전에 참조할 수 없음
console.log(x3); // Cannot access 'x3' before initialization
x3 = 100;
console.log(x3); // 100
function hello() { // 함수선언문
console.log("Hello");
}
var world = function() { // 함수 표현식
console.log("World");
}
var nice = () => { // 함수 표현식 (화살표 함수)
console.log("Nice to Meet You!");
}
-> 다음 장에서 더 자세히 다룰 것
hello(); // Hello, JavaScript
// 함수 선언문 형식으로 정의
function hello() {
console.log("Hello, JavaScript");
}
hello(); // Uncaught TypeError: hello is not a function
var hello = function() {
console.log('Hello, JavaScript!');
};
hello(); // Hello, JavaScript!
위 코드는 아래와 같이 해석
var hello; // undefined 상태
hello(); // Uncaught TypeError: hello is not a function
hello = function() {
console.log('Hello, JavaScript!');
};
hello(); // Hello, JavaScript!
hello(); // Uncaught ReferenceError: Cannot access 'hello' before initialization
let hello = function() {
console.log('Hello, JavaScript!');
};
위 코드는 아래와 같이 해석
let hello; // 초기화되기 전까지 TDZ(Temporal Dead Zone)에 머물러 있다.
hello(); // Uncaught ReferenceError: Cannot access 'hello' before initialization
hello = function() {
console.log('Hello, JavaScript!');
};
function example() {
if (true) {
var x = 10;
}
console.log(x); // 10
}
example();
위 코드에서 if 블록 내부에서 선언된 변수 x는 함수 스코프를 따르기 때문에 블록 외부에서도 접근 가능하게 된다.
이것은 때로 의도치 않은 오류를 초래할 수 있다.
function example() {
var = x = 1
if (true) {
var x = 10; //기존 x를 덮어씀
}
console.log(x); // 10
}
example();
🔥var는 ES6 이전에 사용되던 변수 선언 방식으로, 현재는 의도치 않은 오류를 유발하여 사용이 권장 않고 대신 let과 const 사용을 권장한다.
🔥 값이 변경될 수 있는 변수를 선언할 때 사용한다.
예를 들어, 반복문에서 인덱스 변수나 조건에 따라 값이 변하는 변수를 선언할 때 적합하다.
🔥 값이 변경되지 않는 상수를 선언할 때 사용한다.
객체나 배열을 const로 선언하면 참조 자체는 변경할 수 없지만, 내부의 프로퍼티나 요소는 변경이 가능하다.