실행 컨텍스트 — 함수가 실행될 때 만들어지는 환경
콜 스택에 쌓이는 것의 정체. 변수·this·바깥 스코프로 가는 길이 여기에 담긴다.
Seobway · · 8분
콜 스택에 쌓이는 것은 정확히 무엇인가
콜 스택에 "함수가 쌓인다"고 했지만, 쌓이는 것은 함수 자체가 아니다.
쌓이는 것은 그 호출을 실행하는 데 필요한 환경 한 벌이고, 이것을 실행 컨텍스트라 부른다.
같은 함수를 두 번 호출하면 환경도 두 벌 생긴다. 그래서 각 호출의 지역 변수가 섞이지 않는다.
function greet(name) {
const message = `안녕, ${name}`;
return message;
}
greet("A"); // message = "안녕, A" ← 이 호출만의 환경
greet("B"); // message = "안녕, B" ← 별개의 환경
실행 컨텍스트는 무엇을 담는가
실행 컨텍스트는 함수가 실행될 때 만들어지는 환경이고, 세 가지를 담는다.
| 담기는 것 | 하는 일 |
|---|---|
| 환경 레코드(Environment Record) | 이 호출의 매개변수·지역 변수·함수 선언을 담는 장부 |
| 바깥 환경 참조(outer) | 여기 없는 이름을 찾으러 갈 다음 장소. 이게 이어지면 스코프 체인 |
| this 바인딩 | 이 호출에서 this 가 가리킬 값 |
핵심은 outer 가 "호출한 곳"이 아니라 "함수가 정의된 곳"을 가리킨다는 것이다.
그래서 자바스크립트가 렉시컬 스코프를 따르고, 코드를 읽는 것만으로 어떤 변수가 쓰일지
확정할 수 있다.
인터랙티브 다이어그램: 컨텍스트가 만들어지고 이름을 찾는 과정 (단계별로 재생할 수 있다)
- 스크립트가 시작되면 전역 실행 컨텍스트부터 만들어진다.
- outer() 를 호출하면 그 호출만의 컨텍스트가 새로 생긴다.
- outer 안에서 inner() 를 호출한다. 또 한 벌이 생긴다.
- inner 안에서 이름을 찾는다. 자기 환경 레코드에 없다.
- outer 참조를 따라 바깥으로 나간다. outer 컨텍스트에서 찾았다.
- inner 가 반환되면 그 컨텍스트는 스택에서 사라진다.
만들어질 때 두 단계를 거친다
컨텍스트가 만들어지는 순간과 코드가 한 줄씩 도는 순간은 다르다.
스코프 안의 선언을 먼저 훑어 환경 레코드에 등록한다.this 도 이때 정해진다.
var→ 등록 +undefinedlet·const→ 등록만, 값 없음 → TDZ- 함수 선언 → 몸통까지 통째로
코드를 위에서부터 한 줄씩 실행하며 값을 채운다.
let x = 1 줄에 도달해야 비로소 x 를 쓸 수 있다.
그 전에 읽으면 ReferenceError.
호이스팅이 "선언이 위로 올라간 것처럼 보이는 현상"인 이유가 이것이다.
올라가는 게 아니라 생성 단계에서 먼저 등록되는 것이다.
직접 확인
같은 함수를 두 번 불러 환경이 따로인지, outer 가 정의된 위치를 따르는지 확인해라.
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 를 보지 못한다. outer 가 정의된 위치인
전역을 가리키기 때문이다.
흔한 실수
한 줄 정리
실행 컨텍스트는 함수 호출마다 만들어지는 환경 한 벌이고, 환경 레코드 · 바깥 환경 참조 ·this 를 담는다. 콜 스택에 쌓이는 것이 바로 이것이며, outer 는 호출한 곳이 아니라
정의된 곳을 가리킨다.
- 콜 스택에 쌓이는 것이 무엇인지 한 문장으로 말할 수 있다
- 생성 단계와 실행 단계가 나뉘는 이유를 안다
-
outer가 정의 위치를 따르는 것을 예제로 보일 수 있다
참고
- [1] Executable Code and Execution Contexts — ECMAScript 사양
- [2] Environment Records — ECMAScript 사양
- [3] Call stack — MDN Web Docs 용어 사전
관련 글
- 스코프 — 변수가 어디까지 보이는가 → — 이 글의 선행
- 콜 스택 — 지금 실행 중인 함수를 쌓아 두는 곳 → — 이 글의 선행
- 클로저 — 함수가 붙잡고 있는 변수 → — 컨텍스트가 사라져도 환경이 남는 경우
- javascript
- 실행컨텍스트
- 스코프체인