실행 컨텍스트의 구성과 생성 과정
콜 스택에 push 되는 단위인 실행 컨텍스트의 구성 요소(환경 레코드, 외부 환경 참조, this 바인딩)와 생성 단계·실행 단계를 정리한다.
Seobway · · 8분
문제 상황
콜 스택에는 함수 객체가 아니라 함수 호출마다 생성되는
실행 컨텍스트(Execution Context) 가 push 된다.
같은 함수를 두 번 호출하면 실행 컨텍스트도 두 개 생성된다. 따라서 호출마다 지역 변수가 분리된다.
function greet(name) {
const message = `안녕, ${name}`;
return message;
}
greet("A"); // message = "안녕, A" (첫 번째 호출의 환경)
greet("B"); // message = "안녕, B" (두 번째 호출의 환경)
구성 요소
실행 컨텍스트는 코드 실행에 필요한 상태를 담는 명세상의 구조이며, 주요 구성 요소는 다음과 같다.
| 구성 요소 | 역할 |
|---|---|
| 환경 레코드(Environment Record) | 해당 호출의 매개변수, 지역 변수, 함수 선언의 식별자 바인딩을 저장 |
외부 환경 참조([[OuterEnv]]) |
현재 환경에 없는 식별자를 검색할 상위 환경. 이 연결이 스코프 체인이다 |
| this 바인딩 | 해당 호출에서 this 가 가리키는 값 |
외부 환경 참조는 함수를 호출한 위치가 아니라 함수가 정의된 위치의 환경을 가리킨다.
이것이 렉시컬 스코프이며, 식별자가 어느 선언에 연결되는지는 코드 구조만으로 결정된다.
인터랙티브 다이어그램: 실행 컨텍스트 생성과 식별자 검색 (단계별로 재생할 수 있다)
- 스크립트 실행이 시작되면 전역 실행 컨텍스트가 생성된다.
- outer() 를 호출하면 해당 호출의 실행 컨텍스트가 생성된다.
- outer 안에서 inner() 를 호출한다. inner 의 실행 컨텍스트가 생성된다.
- inner 에서 식별자를 검색한다. inner 의 환경 레코드에는 해당 바인딩이 없다.
- 외부 환경 참조를 따라 outer 의 환경 레코드를 검색하고, 바인딩을 찾는다.
- inner 가 반환되면 해당 실행 컨텍스트는 콜 스택에서 제거된다.
생성 단계와 실행 단계
실행 컨텍스트는 생성 단계에서 선언을 먼저 처리한 뒤 실행 단계에서 코드를 순서대로 평가한다.
스코프 안의 선언을 환경 레코드에 등록한다.
함수 호출이라면 this 바인딩도 이때 결정된다.
var: 바인딩 생성 후undefined로 초기화let·const: 바인딩만 생성, 초기화하지 않음 (TDZ)- 함수 선언: 바인딩 생성 후 함수 객체로 초기화
코드를 위에서부터 평가하며 바인딩에 값을 할당한다.
let x = 1 문이 평가된 뒤에야 x 에 접근할 수 있다.
그 전에 접근하면 ReferenceError 가 발생한다.
호이스팅은 이 생성 단계의 결과다. 코드가 이동하는 것이 아니라,
실행 전에 선언이 환경 레코드에 먼저 등록된다.
예제
같은 함수를 두 번 호출했을 때 환경이 분리되는지, 외부 환경 참조가 정의 위치를 따르는지 확인한다.
const where = "전역";
function show() {
console.log("show 가 보는 where:", where);
}
function run() {
const where = "run 안"; // show 의 스코프 체인과 무관하다
show();
console.log("run 이 보는 where:", where);
}
run();
// 호출마다 별도의 환경 레코드가 생성된다
function counter() {
let n = 0;
return () => ++n;
}
const a = counter();
const b = counter();
console.log("a:", a(), a()); // 1 2
console.log("b:", b()); // 1 (a 와 다른 환경)
show 는 run 안에서 호출되지만 run 의 where 에 접근하지 않는다. show 의 외부 환경 참조가
정의 위치인 전역 환경을 가리키기 때문이다.
자주 하는 실수
정리
실행 컨텍스트는 함수 호출마다 생성되며 환경 레코드, 외부 환경 참조, this 바인딩을 포함한다.
콜 스택에 push 되는 단위가 이것이고, 외부 환경 참조는 호출 위치가 아니라 정의 위치를 가리킨다.
- 콜 스택에 push 되는 단위가 무엇인지 설명할 수 있다
- 생성 단계와 실행 단계에서 각각 일어나는 일을 안다
- 외부 환경 참조가 정의 위치를 따른다는 것을 예제로 보일 수 있다
참고
- [1] Executable Code and Execution Contexts — ECMAScript 사양
- [2] Environment Records — ECMAScript 사양
- [3] Call stack — MDN Web Docs 용어 사전
관련 글
- 스코프와 스코프 체인 → (선행 개념)
- 콜 스택과 함수 호출 순서 → (선행 개념)
- this 바인딩 규칙 → (다음 글)
- 클로저와 렉시컬 환경 → (실행 컨텍스트 제거 후에도 환경이 유지되는 경우)
- javascript
- 실행컨텍스트
- 스코프체인