Chapter 8

실행 컨텍스트와 클로저

  • 8.1 소스코드의 타입
  • 8.2 소스코드의 평가와 실행
  • 8.3 실행 컨텍스트의 역할
  • 8.4 실행 컨텍스트 스택
  • 8.5 렉시컬 환경
  • 8.6 실행 컨텍스트의 생성과 식별자 검색 과정
  • 8.7 렉시컬 스코프
  • 8.8 함수 객체의 내부 슬롯 [[Environment]]
  • 8.9 클로저와 렉시컬 환경
  • 8.10 클로저의 활용
  • 8.11 캡슐화와 정보 은닉

JS 엔진의 동작 원리인 실행 컨텍스트와, 그 위에서 작동하는 클로저까지 한 흐름으로 정리해볼게. 스코프, 호이스팅, 클로저를 근본적으로 이해하려면 이 두 개념이 반드시 필요하거든.

JS 엔진은 소스코드를 4가지 타입으로 구분하고, 각각 실행 컨텍스트를 생성해. 전역 코드는 전역 실행 컨텍스트, 함수 코드는 함수 실행 컨텍스트, eval 코드는 eval 실행 컨텍스트, 모듈 코드는 모듈 실행 컨텍스트를 만들지.

소스코드 처리는 2단계로 나뉘어. 먼저 평가(Evaluation) 단계에서 실행 컨텍스트를 생성하고, 변수/함수 선언문을 먼저 실행해서 식별자를 등록해. 이게 바로 호이스팅의 정체야. 그다음 실행(Execution) 단계에서 런타임에 코드를 한 줄씩 실행하면서 값을 할당하고 참조하지.

실행 컨텍스트는 스택 자료구조로 관리돼. 함수 호출하면 새 실행 컨텍스트가 push되고, 함수 종료하면 pop되지. 스택 최상위가 현재 실행 중인 코드야.

실행 컨텍스트의 핵심 컴포넌트는 렉시컬 환경이야. 식별자와 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조지. **환경 레코드(Environment Record)**가 식별자와 값을 등록/관리하고, **외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference)**가 상위 스코프를 가리켜. 이게 바로 스코프 체인을 구현하는 메커니즘이야.

식별자를 검색할 때는 현재 실행 컨텍스트의 렉시컬 환경에서 먼저 찾고, 없으면 외부 렉시컬 환경 참조를 따라 상위 스코프로 올라가. 전역 렉시컬 환경까지 가서도 없으면 ReferenceError가 발생하지.

이 렉시컬 환경의 원리를 이해했으면 클로저로 넘어갈 수 있어. 먼저 렉시컬 스코프를 복습하자면, 함수의 상위 스코프는 함수가 정의된 위치에 의해 결정돼. 호출 위치가 아니야. 함수는 정의될 때 자신의 상위 스코프를 [[Environment]] 내부 슬롯에 저장해. 이 참조 덕분에 함수가 어디서 호출되든 자신이 정의된 스코프를 기억하는 거야.

그러면 클로저가 뭐냐? 외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수가 이미 종료된 외부 함수의 변수를 참조할 수 있어. 이런 중첩 함수를 클로저라고 해.

function outer() {
  let x = 10;
  function inner() { console.log(x); }
  return inner;
}
const closure = outer(); // outer는 종료됨
closure(); // 10 — 여전히 x에 접근 가능!

외부 함수가 종료되어도, 반환된 내부 함수의 [[Environment]]가 외부 함수의 렉시컬 환경을 참조하고 있으니까 가비지 컬렉션 대상이 되지 않는 거야.

클로저의 핵심 활용은 상태를 안전하게 은닉하고, 특정 함수에게만 상태 변경을 허용하는 패턴이야.

function counter() {
  let num = 0; // 외부에서 직접 접근 불가
  return {
    increase() { return ++num; },
    decrease() { return --num; },
  };
}
const c = counter();
c.increase(); // 1
c.increase(); // 2
c.decrease(); // 1

JS에는 private 키워드가 없었지만(ES2022에 # 도입), 클로저를 활용하면 private 변수를 흉내 낼 수 있어. 다만 프로토타입 메서드에서 private 변수에 접근하는 건 한계가 있지.


정리

8장 읽고 기억할 거 세 가지:

  1. 실행 컨텍스트는 코드의 실행 순서와 스코프를 관리하는 핵심 메커니즘이야. 호이스팅은 평가 단계에서 식별자가 먼저 등록되기 때문에 일어나는 거고, 스코프 체인은 렉시컬 환경의 외부 참조로 구현돼.
  2. 클로저 = 함수 + 그 함수가 선언된 렉시컬 환경이야. 외부 함수가 종료되어도 내부 함수가 상위 스코프를 기억하는 거지.
  3. 클로저는 상태 은닉과 캡슐화의 핵심 도구야. React의 useState 같은 훅도 클로저 기반이니까, 프레임워크 내부를 이해하려면 확실히 알아둬야 해.