Hoisting
console.log(a); // 1 ?!
var a = 1;
자바스크립트 단골 질문인 호이스팅이다
호이스팅 자체는 어떻게든 이해가 가더라도, 그 원리까지 공부하자니 온갖 선행 개념들이 많아 이 김에 정리해볼까 한다
왜 발생하고 어떻게 발생하는지 알아보도록 하자
설명

Hoist라는 영단어는 무언가를 끌어 올린다는 뜻을 가지고 있다
뜻을 풀었으니 한줄요약하자면 호이스팅은 변수나 함수의 선언을 맨 위로 끌어올린 것처럼 동작하는 현상이다
실제로 변수나 함수 선언이 최상단으로 끌어올려진 것은 아니고, 자바스크립트 엔진의 특성상 끌어올려진 것 처럼 동작하는 것 뿐이라고 한다
발생 이유
https://chichoon.tistory.com/921
실행 컨텍스트에 대해 필독하고 오자 (호이스팅은 실행 컨텍스트로 설명되기 때문)
사실 이 문서와 실행 컨텍스트 문서를 같이 작성하려다가 저 쪽이 너무 길어져서 분리했다
세줄요약 하자면
- 함수가 실행될 때 실행 컨텍스트가 생성되고, 그 후 실행된다
- 실행 컨텍스트가 생성되고 실행되기 전에 모든 변수나 함수의 선언부가 메모리에 등록된다
- 따라서 실행 컨텍스트가 실행되었을 때는 이미 변수와 함수의 선언이 등록된 이후이므로 변수와 함수 선언부가 코드 최상단으로 끌어올려진 것처럼 동작하게 된다
호이스팅이 발생하는 부분
var
console.log(a); // undefined
var a = 1;

var은 호이스팅이 발생하는 대표적인 예시이다
위의 예시를 보면 선언 전에 값에 접근했음에도 오류가 나지 않고 실행되는 것을 볼 수 있다
선언만 끌어올려졌을 뿐 할당은 아직 일어나지 않았으므로, a는 undefined로 초기화되어 저장된다
따라서 undefined가 출력되는 것
let, const와 TDZ
console.log(a); // a is not defined
let a = 1;

let과 const는 선언 전에 값을 사용하면 ReferenceError 오류가 발생하므로 호이스팅이 발생하지 않는 것처럼 보인다
하지만 let과 const도 (실행 컨텍스트 생성 시에 메모리에 적재되는 것은 똑같으므로) 호이스팅이 발생하고, 마치 호이스팅이 발생하지 않는 것처럼 보이는 것 뿐…
왜 let과 const는 호이스팅이 일어나지 않는 것처럼 보이는지 알고 싶다면 TDZ (Temporal Dead Zone) 을 알아야 한다
TDZ는 일시적 사각지대… 이라는 이름에서 알 수 있듯, 변수나 클래스 등이 일시적으로 접근 불가 상태에 빠지는 것을 말한다
let과const는 선언 시점에서 실행 컨텍스트에 등록된다- 하지만
undefined로 임시 초기화되던var와 달리,let과const는 초기화가 되지 않는다 (정확히 말하자면,uninitialized상태로 초기화된다) let,const는 처음 값을 할당받는 (초기화되는) 코드를 마주할 때까지 TDZ에 빠지고, 이 상태에서let과const에 접근하면ReferenceError가 발생한다
클래스
const b = new TestClass();
class TestClass {}

클래스 또한 TDZ의 영향을 받으며, 메모리에 적재되는 건 같지만 uninitialized 상태로 초기화되어 실질적인 클래스 선언 전까지 사용이 불가능하다
함수 선언문
foo();
function foo() {
console.log("hihi");
}

함수 선언문은 호이스팅이 일어나며, 변수 등등과 다르게 undefined로 초기화되지 않고 아예 실행 컨텍스트가 생성되는 방식이기 때문에 함수를 호출해도 정상적으로 동작한다
덕분에 함수 순서를 조금 더 유연하게 배치할 수 있게 되는 것
함수와 클래스 표현식
foo();
var foo = function () {
console.log("hihi");
};

const b = new TestClass();
var TestClass = class {
constructor() {
console.log("hihi");
}
};

함수 표현식과 클래스 표현식은 변수 안에 함수를 넣고 이를 호출하는 방식인데, 호이스팅 개념을 생각해 보면 처음 변수 foo와 TestClass 는 실행 컨텍스트 적재 시점에 undefined로 초기화되므로 함수를 호출하거나 생성자를 호출할 수 없다
console.log(foo);
var foo = function () {
console.log("hihi");
};

실제로 foo 에 함수를 할당하기 전 출력해 보면 undefined가 찍히는 것을 볼 수 있다
참고 자료
https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/