본문 바로가기

3일차 호이스팅과 TDZ: 자바스크립트는 왜 내 변수를 숨겼을까? (feat. Call Stack)

1. 문제의 시작: "코드는 위에서 아래로 실행된다?"

자바스크립트를 처음 배울 때 가장 많이 하는 착각은 "코드가 무조건 1번 줄부터 순서대로 실행된다"는 것입니다. 하지만 개발을 하다 보면, 선언하지도 않은 함수가 실행되거나(var), 반대로 분명히 선언했는데 에러가 나는(let) 기이한 현상을 마주하게 됩니다.

오늘 나는 자바스크립트 엔진이 코드를 실행하기 전 거치는 **'준비 단계(Creation Phase)'**를 통해 이 현상의 원인을 파헤쳐 보았습니다.

2. 호이스팅(Hoisting)과 TDZ의 진실

가장 헷갈렸던 부분은 var와 let의 동작 차이였습니다.

[실험 코드]

 
// 상황 1: var
console.log(name); // undefined (에러 안 남!)
var name = "Gildong";

// 상황 2: let
console.log(age); // ReferenceError: Cannot access 'age' before initialization
let age = 20;

[원리 분석] 자바스크립트 엔진은 코드를 실행하기 전, 마치 조연출이 대본을 훑듯 변수와 함수의 이름을 미리 파악해 메모리에 등록합니다. 이를 **호이스팅(Hoisting)**이라고 합니다.

  • var의 경우: 이름을 등록하면서 undefined라는 값으로 초기화까지 시켜버립니다. 그래서 무대에 등장하기도 전에 호출해도 "값은 없지만 누군지는 알아"라고 대답하는 것입니다.
  • let/const의 경우: 이름은 등록(호이스팅)되지만, 실제 선언 줄에 도달할 때까지 초기화를 미룹니다. 이 구간을 **TDZ(Temporal Dead Zone, 일시적 사각지대)**라고 부릅니다.

즉, 엔진은 age라는 변수가 있다는 걸 알고 있었지만, **"안전하게 값이 할당되기 전까진 절대 접근 금지"**라며 에러를 던진 것입니다. 이는 버그를 막기 위한 안전장치입니다.

3. 실행 컨텍스트와 Call Stack (호출 스택)

변수 처리가 끝나면 엔진은 실제로 코드를 실행합니다. 이때 함수 호출 순서를 관리하는 곳이 바로 **Call Stack(호출 스택)**입니다.

[직접 구현한 Stack 구조]

 
function third() {
  console.log("3. 세 번째 함수 실행 중..."); // (3) 가장 나중에 들어와서 가장 먼저 끝남
}

function second() {
  console.log("2. 두 번째 함수 실행 중...");
  third(); // third 함수를 스택에 Push
  console.log("2. 두 번째 함수 종료 직전");
}

function first() {
  console.log("1. 첫 번째 함수 실행 중..."); // (1) 가장 먼저 들어옴
  second(); // second 함수를 스택에 Push
  console.log("1. 첫 번째 함수 종료 직전");
}

first();

[실행 결과]

1. 첫 번째 함수 실행 중...
2. 두 번째 함수 실행 중...
3. 세 번째 함수 실행 중...
2. 두 번째 함수 종료 직전
1. 첫 번째 함수 종료 직전

이 구조는 LIFO(Last In, First Out), 즉 '프링글스 통'과 같습니다. 나중에 들어간 third가 끝나야 second가 끝날 수 있고, second가 끝나야 first가 끝납니다.

4. 현업 인사이트 (Learned)

  • 에러 로그 보는 법: 브라우저 콘솔의 에러 메시지(Stack Trace)가 바로 이 Call Stack의 스냅샷이라는 점을 배웠습니다. 에러가 발생했을 때 맨 윗줄부터 차례로 내려가면 "누가 범인을 불렀는지" 추적할 수 있습니다.
  • Stack Overflow: 만약 함수가 멈추지 않고 계속 서로를 부르면(재귀), 프링글스 통이 넘쳐버리는 Maximum call stack size exceeded 에러가 발생합니다.

5. 결론

"변수 선언은 무조건 최상단에 하라"는 코딩 컨벤션이 왜 생겼는지 이해하게 되었습니다. TDZ 에러를 피하고, 스코프를 명확히 하여 예측 가능한 코드를 짜는 것이 '기본기가 튼튼한 개발자'가 되는 첫걸음입니다.

컴공이지만 코딩 못함 잘하면 이름 바꿀거임
@컴공이지만 코딩 못함 잘하면 이름 바꿀거임 :: 맥북 산 김에 개발하기

맥북 산 김에 코딩 공부 열심히 해서 개발이나 해보겠습니다.

열심히 해보겠습니다

목차