실행 컨텍스트란, 함수가 실행될 때 그 당시의 문맥, 전후 사정을 말한다.
이로 인해, 흔히들 실행할 코드에 제공할 환경 정보를 모아놓은 객체라도 말한다.
실행 컨텍스트는 스코프, 호이스팅, 외부 환경 정보 구성, this값 설정 등의 기능을 한다.
자바스크립트 엔진은 코드를 실행하기 위하여 실행에 필요한 여러가지 정보를 알고 있어야 한다.
이와 같이 실행에 필요한 정보를 형상화하고, 구분하기 위해 자바스크립트 엔진은 실행 컨텍스트를 물리적 객체의 형태로 보관한다.
| 타입 | 설명 | 종류 |
|---|---|---|
| 전역 코드 | 전역에 존재하는 소스코드 | 전역 실행 컨텍스트(Global Execution Context) |
| 함수 코드 | 함수 내부에 존재하는 소스코드 | 함수 실행 컨텍스트(Functional Execution Context) |
| eval 코드 | 빌트인 전역 함수인 eval 함수에 인수로 전달되어 실행되는 소스코드 | Eval Function Execution Context |
자동으로 생성되는 전역공간과 eval을 제외하면, 실행 컨텍스트가 생성되는 시점은 곧 함수를 실행하는 시점.
자바스크립트 엔진은 소스 코드를 평가와 실행의 과정으로 나누어 처리합니다.
실행 컨텍스트는 콜 스택이라는 자료구조에 의해 관리된다.
콜스택은 JS 엔진이 가지고 있고, 코드가 실행되면 시간의 흐름에 따라 콜 스택에는 다음과 같이 실행 컨텍스트가 추가되고 제거된다.

JS 엔진은 함수가 실행되면 해당 함수에 대한 실행 컨텍스트를 생성한 후, 콜 스택에 추가한다.
그리고 소수 코드의 평가와 실행 과정을 반복하며 코드를 실행해 나간다.
const x = 1;
function funcA() {
const y = 2;
function fucnB() {
const z = 3;
console.log(x + y + z);
}
funcB();
}
funcA();
x, 전역 함수 funcA를 실행 컨텍스트에 등록x에 값 할당, 전역 함수 funcA 호출funcA 함수 코드의 평가funcA 가 호출되면서 전역 코드의 실행은 일시 중단 및 코드 제어권이 funcA 함수 내부로 이동funcA 함수 실행 컨텍스트 생성y, 중첩 함수 funcB를 funcA의 실행 컨텍스트에 등록funcA 함수 코드의 실행y에 값 할당funcB 호출funcB 함수 코드의 평가funcB가 호출되면서 funcA의 실행은 일지 중단 및 코드 제어권이 funcB 함수 내부로 이동funcB 함수 실행 컨텍스트 생성z를 funcB 의 실행 컨텍스트에 등록funcB 함수 코드의 실행z에 값 할당funcB 함수 종료funcA 함수 코드로 복귀funcB 함수 실행 컨텍스트를 콜 스택에서 pop 하여 제거funcA 함수 종료funcA 함수 실행 컨텍스트를 콜 스택에서 pop 하여 제거이러한 스택의 구조로 코드의 실행 순서를 보장하며,
콜 스택의 최상단에 존재하는 실행 컨텍스트는 항상 현재 실행중인 코드의 실행컨텍스트이다.
실행 컨텍스트 내에는 variable environment, lexical Environment, this binding가 존재한다.
호이스팅
JS 엔진이 실행 컨텍스트를 구성할 때, environmentRecord에 식별자의 정보를 수집한다.
이러한 과정을 통해 JS 엔진은 함수를 실행하기도 전에 해당 컨텍스트 내부의 변수명들을 이미 알고있다.
이렇기에 실별자들을 코드의 최상단으로 끌어올렸다 라는 뜻의 호이스팅이라는 개념이 생겨나게 되었다.
물리적으로 끌어올린 것이 아닌, 실행 컨텍스트 관점에서 이미 식별자들의 정보를 알고 있기에, 식별자 정보를 수집하는 과정을 이해하기 쉬운 방법으로 나타낸 추상화 한 가상의 개념이다.
➡️ Lexical Environment의 environmentRecord의 경우, 해당 컨텍스트 환경에 필요한 식별자와 그 값이 기록되며, 함수 실행 시 실행 컨텍스트가 생성되므로 (함수 실행보다 environmentRecord 수집이 먼저) 변수와 같은 식별자를 끌어올리는 것과 같다 라는 개념의 호이스팅이 탄생하게 된 것이다.
this 는 현재 컨텍스트를 가리킨다. method에서 사용 시, 해당 method가 담겨있는 instance나 object를 가리키며, 함수 표현식에서 사용 시, this 바인딩을 하지 않는 이상 전역 객체를 가리킴
함수 내부에서 전역 변수에 접근이 가능한 이유이다.
함수 내부에서 해당 함수를 선언했을 당시의 환경에 접근이 가능하도록 참조를 하는 것이다.
const global = "I'm GLOBAL";
function outerFunc() {
const outer = "I'm OUTER";
function innerFunc() {
const inner = "I'm INNER";
console.log(global, outer, inner);
}
innerFunc();
}
outerFunc();
위의 코드를 실행해보면, 순서대로,
I'm GLOBAL I'm OUTER I'm INNER 이라는 출력값을 가지게 된다.
이게 내부적으로 어떻게 가능한것일까?
먼저, innerFunc 의 기준에서 보면, innerFunc의 외부 환경은 outerFunc의 렉시컬 환경인 것이다.
나아가, outerFunc의 외부 환경은 전역 객체의 렉시컬 환경인 것이다.
innerFunc는 외부 환경 참조를 통해 outerFunc 내부의 변수들에 접근이 가능한 것이고, outerFunc 또한 외부 환경 참조를 통해 전역 변수인 global 변수에 접근이 가능한 것이다. 이렇게 연쇄적인 외부 환경 참조가 발생되어, innerFunc 안에서도 전역 변수에 접근이 가능한 것이다.
이렇게 연쇄적으로 발생되는 외부 환경 참조를 스코프 체이닝 이라고 한다.
외부 환경 참조가 체인을 연결하는 것처럼 연쇄적으로 이루어져, 함수의 depth가 얼마나 깊던지 간, 해당 함수는 전역 변수에 접근이 가능하게 되는 것이다.