Ray Book
실행 컨텍스트와 스코프

실행 컨텍스트란 무엇인가

JavaScript가 코드를 실행할 때 만들어지는 환경 — 실행 컨텍스트의 구조, 생성/실행 단계, 콜스택을 시각화합니다

javascriptexecution-contextcall-stackhoisting

코드를 실행하려면 환경이 필요하다

var x = 10이라는 코드를 실행하려면, 엔진은 몇 가지를 알아야 합니다:

  • x라는 변수를 어디에 저장할 것인가?
  • 이 코드의 this무엇 을 가리키는가?
  • 바깥 스코프에 있는 변수에 어떻게 접근할 것인가?

이 정보를 담고 있는 것이 실행 컨텍스트 (Execution Context) 입니다. JavaScript 엔진은 코드를 실행하기 전에 반드시 실행 컨텍스트를 먼저 생성합니다.

실행 컨텍스트의 종류

JavaScript에는 세 종류의 실행 컨텍스트가 있습니다:

  • 전역 실행 컨텍스트 — 스크립트가 시작될 때 딱 하나 생성. window (브라우저) 또는 global (Node.js) 객체와 연결
  • 함수 실행 컨텍스트 — 함수가 호출될 때마다 생성. 같은 함수를 10번 호출하면 10개의 컨텍스트가 생성됨
  • eval 실행 컨텍스트eval() 호출 시 생성 (거의 쓰이지 않음)

실행 컨텍스트의 두 단계

각 실행 컨텍스트는 생성 단계실행 단계 를 거칩니다.

생성 단계 (Creation Phase)

코드를 실행하기 전에 일어납니다:

  1. this 바인딩 결정
  2. 변수/함수 선언을 찾아서 메모리에 등록
    • var 변수 → undefined로 초기화
    • 함수 선언 → 함수 객체로 초기화 (전체가 메모리에 올라감)
    • let/const → 등록되지만 초기화되지 않음 (TDZ)
  3. 외부 환경 참조 설정 (스코프 체인)

이것이 바로 호이스팅 의 실체입니다. 코드가 "끌어올려지는" 것이 아니라, 생성 단계에서 선언이 먼저 처리되는 것입니다.

실행 단계 (Execution Phase)

코드를 한 줄씩 실행합니다. 변수에 값을 할당하고, 함수를 호출하고, 표현식을 평가합니다.

콜스택과 실행 컨텍스트

함수가 호출되면 새 실행 컨텍스트가 콜스택에 push되고, 함수가 반환되면 pop됩니다. 아래 시각화에서 중첩 함수 호출 시 콜스택이 어떻게 변하는지 확인하세요.

코드
1var x = 10;
2function foo() {
3 var y = 20;
4 function bar() {
5 var z = 30;
6 return x + y + z;
7 }
8 return bar();
9}
10foo();
콜 스택
GGlobal
생성 단계
xundefinedfoofunctionthiswindow
스크립트가 시작되면 전역 실행 컨텍스트가 생성됩니다. 생성 단계에서 var 변수는 undefined로, 함수 선언은 함수 객체로 초기화됩니다.

핵심 관찰:

  • 생성 단계 에서 var yundefined로 초기화된 것을 볼 수 있습니다 — 이것이 호이스팅
  • 함수 선언 (bar) 은 생성 단계에서 바로 함수 객체로 초기화됩니다
  • bar() 안에서 x를 찾을 때, 자신의 컨텍스트 → foo → Global 순서로 스코프 체인 을 탐색합니다
  • 함수가 반환되면 컨텍스트가 pop 됩니다 — LIFO 순서

실행 컨텍스트의 내부 구조

ECMAScript 명세에 따르면 실행 컨텍스트는 이런 구성 요소를 가집니다:

LexicalEnvironment

let, const, 함수 선언이 저장되는 환경. 환경 레코드 (Environment Record) 와 외부 환경 참조 (Outer Reference) 로 구성됩니다.

VariableEnvironment

var 변수가 저장되는 환경. 함수/전역 수준에서는 LexicalEnvironment와 같은 객체를 가리킵니다. 하지만 let/const가 포함된 블록에 진입하면 LexicalEnvironment가 새 환경으로 교체되는 반면, VariableEnvironment는 그대로 유지됩니다 — 이것이 var가 블록을 무시하고 함수 스코프에 속하는 이유입니다.

ThisBinding

현재 컨텍스트의 this 값. 전역에서는 window, 메서드 호출에서는 호출 객체, new에서는 새 인스턴스를 가리킵니다. (5편에서 자세히 다룹니다)

호이스팅 다시 보기

실행 컨텍스트를 이해하면 호이스팅이 더 이상 마법이 아닙니다:

console.log(a);   // undefined (var — 생성 단계에서 undefined로 초기화)
console.log(b);   // ReferenceError (let — 생성 단계에서 등록만, 초기화 안 됨)
console.log(foo); // function (함수 선언 — 생성 단계에서 전체가 초기화)

var a = 1;
let b = 2;
function foo() {}
  • var a — 생성 단계에서 undefined로 초기화 → 접근 가능하지만 값은 undefined
  • let b — 생성 단계에서 등록만 → 초기화 전 접근 시 ReferenceError (TDZ)
  • function foo — 생성 단계에서 함수 객체로 초기화 → 선언 전에도 호출 가능

정리

실행 컨텍스트는 JavaScript 실행의 기본 단위 입니다:

  • 코드가 실행되려면 반드시 실행 컨텍스트가 필요하다
  • 전역 컨텍스트는 하나, 함수 컨텍스트는 호출마다 생성
  • 생성 단계에서 변수/함수를 등록하고 (→ 호이스팅), 실행 단계에서 코드를 수행
  • 콜스택이 실행 컨텍스트의 생명주기를 관리

다음 단계

실행 컨텍스트가 "외부 환경 참조"를 통해 바깥 변수에 접근한다고 했습니다. 이 참조가 어떻게 연결되고, 변수를 찾을 때 어떤 순서로 탐색하는지 — 다음 글에서 스코프와 스코프 체인 을 자세히 살펴보겠습니다.