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

실행 컨텍스트란 무엇인가

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

javascriptexecution-contextcall-stackhoisting

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

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

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

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

실행 컨텍스트의 종류

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

  • 전역 실행 컨텍스트 , 스크립트가 시작될 때 딱 하나 생성. window (브라우저) 또는 globalThis (Node.js, 구 global) 객체와 연결
  • 함수 실행 컨텍스트 , 함수가 호출될 때마다 생성. 같은 함수를 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와 같은 객체를 가리킵니다. var 선언은 선언 인스턴스화 단계에서 가장 가까운 함수/전역/모듈의 VariableEnvironment에 등록되므로, 중간에 어떤 블록이 있어도 블록에 묶이지 않고 함수 스코프에 귀속됩니다. 반면 let/const는 블록 진입 시 새로 만들어지는 LexicalEnvironment에 바인딩되어 블록 스코프를 가집니다.

ThisBinding

현재 컨텍스트의 this 값. 클래식 스크립트의 전역에서는 전역 객체 (window) 를 가리키지만, ES 모듈의 최상위에서는 undefined입니다. 메서드 호출에서는 호출 객체, 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 실행의 기본 단위 입니다.

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

다음 단계

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