JS 엔진은 코드 실행 전 소스코드 평가 단계를 통해 코드를 평가합니다.
이 과정에서 실행 컨텍스트가 생성되며, 선언문을 먼저 처리한 후 본격적인 코드를 실행합니다.
실행 컨텍스트는 코드 실행에 필요한 환경 정보를 모아놓은 객체로 현재 활성화된 실행 컨텍스트는 call stack에서 최상단에 있는 컨텍스트입니다.
실행 컨텍스트의 역할
- 식별자 결정 -> 변수, 함수, 객체를 어디에서 어떻게 참조할지 결정
- 스코프 체인 관리 -> 상위 스코프를 참조하여 변수 탐색
- this 바인딩 -> 실행 컨텍스트별로 this가 가리키는 객체 결정
실행 컨텍스트의 종류
전역 실행 컨텍스트
JS 코드가 실행될 때 가장 먼저 생성
Window, Global이 전역 객체가 됨
프로그램이 종료될 때까지 유지
함수 실행 컨텍스트
함수가 호출될 때마다 생성됨
함수가 종료되면 컨텍스트 스택에서 제거
실행 컨텍스트는 내부적으로 렉시컬 환경(=== 정적 환경, 위부 환경 참조 + 환경 레코드)으로 구성됩니다.
환경 레코드
외부 환경 참조
Reference Error null변수 섀도잉 (Variable Shadowing)
같은 이름의 변수가 하위 스코프에서 선언될 경우, 상위 스코프의 변수가 가려지는 현상
const x = 1;
function outer() {
const y = 2;
function inner() {
const z = 3;
console.log(x, y, z);
}
inner();
}
outer(); // 1 2 3
inner() 내부에서 x와 y를 찾을 수 없으므로 스코프 체인을 따라 상위 환경 참조
최종적으로 전역 실행 컨텍스트까지 탐색하여 x를 찾음
소스코드 평가 단계 (Execution Context 생성)
소스코드 실행 단계 (Execution Context 실행)
코드 예제
function first() {
console.log("first");
second();
}
function second() {
console.log("second");
}
first();
console.log("global");
실행 과정
1. 전역 실행 컨텍스트 생성
first, second 함수 선언 등록
2. first() 실행 → 새로운 실행 컨텍스트 생성 및 스택 추가
3. second() 실행 → 새로운 실행 컨텍스트 생성 및 스택 추가
4. second() 실행 종료 → 컨텍스트 스택에서 제거
5. first() 실행 종료 → 컨텍스트 스택에서 제거
6. 전역 코드 실행 완료 → 전역 실행 컨텍스트 유지
실행 컨텍스트 스택 변화
Call Stack: 1. [Global Execution Context] 2. [Global] -> [first Execution Context] 3. [Global] -> [first] -> [second Execution Context] 4. [Global] -> [first] (second 종료) 5. [Global] (first 종료)
실행 컨텍스트
실행 컨텍스트는 JavaScript 코드 실행에 필요한 환경 정보를 담은 객체입니다. 주로 식별자 결정, 스코프 체인 관리, this 바인딩을 담당하며, 내부적으로 렉시컬 환경으로 구성됩니다.
렉시컬 환경
렉시컬 환경은 환경 레코드(변수 및 함수 선언 저장)와 외부 환경 참조(상위 스코프 연결)로 나뉘어, 변수나 함수를 찾을 때 사용됩니다.
동작 과정
실행 컨텍스트는 소스코드 평가와 실행 단계로 동작합니다.
- 평가 단계: 전역 실행 컨텍스트를 생성하고, this를 바인딩하며, 변수와 함수 선언을 환경 레코드에 등록한 뒤 컨텍스트 스택에 추가합니다.
- 실행 단계: 선언문을 제외한 코드를 실행하고, 변수에 값을 할당하거나 함수를 호출합니다.
예를 들어, 함수 호출 시 새로운 실행 컨텍스트가 생성되어 스코프 체인을 따라 변수를 참조합니다.
스코프 체인
스코프 체인은 외부 환경 참조를 통해 상위 렉시컬 환경을 연결하여 변수나 함수를 찾는 메커니즘입니다. 즉, 스코프 체인은 렉시컬 환경의 외부 참조가 동작하는 방식이라고 볼 수 있습니다.
호이스팅(hoisting)은 실행 컨텍스트와 어떻게 관련 있나요?
호이스팅은 소스코드 평가 단계에서 변수와 함수 선언이 환경 레코드에 먼저 등록되는 현상입니다. 실행 컨텍스트가 생성될 때, 평가 단계에서 var, function 선언이 메모리에 등록되므로, 코드 실행 전에 참조가 가능해 보입니다.
this 바인딩은 실행 컨텍스트에서 어떻게 결정되나요?
this 바인딩은 실행 컨텍스트가 생성될 때 결정됩니다. 전역 컨텍스트에서는 window(브라우저)나 global(Node.js)이 기본이고, 함수 컨텍스트에서는 호출 방식에 따라 달라집니다. 예를 들어, 객체 메서드면 this는 해당 객체, 화살표 함수면 상위 스코프의 this를 따릅니다.
순서
0. 실행 컨텍스트는 코드 실행을 위한 환경을 제공
1. 소스코드 평가 단계에서 실행 컨텍스트가 생성됨
2. 환경 레코드에 변수와 함수 선언이 등록됨 (호이스팅 발생)
3. 외부 환경 참조를 통해 상위 컨텍스트 접근 가능 (스코프 체인)
4. 실행 컨텍스트 스택(Call Stack) 으로 코드 실행 순서 관리
5. 함수 실행이 끝나면 컨텍스트 스택에서 제거됨
실행 컨텍스트 스택(콜 스택)은 어떻게 작동하나요?
실행 컨텍스트 스택은 현재 실행 중인 컨텍스트를 관리합니다. 코드 실행 시 전역 컨텍스트가 먼저 스택에 들어가고, 함수 호출마다 새로운 컨텍스트가 스택에 쌓입니다. 함수 실행이 끝나면 해당 컨텍스트가 스택에서 제거됩니다.
예를 들어, 재귀 함수 호출 시 스택이 계속 쌓이고, 실행이 끝날 때마다 하나씩 제거됩니다. 스택 오버플로우는 이 스택이 너무 깊어질 때 발생합니다.
클로저와 실행 컨텍스트는 어떻게 연결되나요?
클로저는 내부 함수가 외부 함수의 렉시컬 환경을 참조할 때, 외부 함수의 실행 컨텍스트가 종료되어도 그 환경이 유지되는 경우입니다. 실행 컨텍스트의 렉시컬 환경이 가비지 컬렉터에 의해 제거되지 않고, 내부 함수가 외부 환경 참조를 통해 접근할 수 있게 합니다.
전역 실행 컨텍스트와 함수 실행 컨텍스트의 차이는?
전역 실행 컨텍스트는 코드 시작 시 단 하나 생성되며, 전역 객체(window 또는 global)와 this를 바인딩하고 전역 변수를 관리합니다. 함수 실행 컨텍스트는 함수 호출마다 생성되며, 해당 함수의 매개변수, 지역 변수, 스코프 체인을 관리합니다.
전역 컨텍스트는 프로그램 종료까지 유지되지만, 함수 컨텍스트는 실행 후 스택에서 제거됩니다.
비동기 함수(async/await)는 실행 컨텍스트와 어떻게 관련 있나요?
비동기 함수도 호출 시 새로운 실행 컨텍스트를 생성합니다. 하지만 await는 실행을 일시 중지하고, 프로미스가 해결될 때까지 컨텍스트가 스택에서 유지되지 않고 마이크로태스크 큐로 관리됩니다. 프로미스 해결 후 컨텍스트가 다시 스택에 들어와 실행이 재개됩니다.