Execution Context는 자바스크립트 코어에서 가장 중요한 부분 중 하나인데, 구글링해보면 옛날 자료를 기반으로 한게 대부분입니다. (절반정도가 ES3...)
그래서 ECMAScript 명세와 여러 포스팅들을 종합해서 최신 자바스크립트(ES2022) Execution Context 동작을 정리하고자 했습니다.
틀린 부분은 댓글로 알려주시면 감사하겠습니다.
Execution Context는 세 가지 경우에 생성된다Global Execution Context: 글로벌 코드가 평가될 때(프로그램 시작)Functional Execution Context: 함수가 호출될 때Eval Function Execution Context: eval() 함수가 실행될 때Call stack size exceeded라는 오버플로우 에러 메세지를 볼 수도 있다Execution Context를 Running Execution Context라고 부른다Execution Context가 중요한 이유는 스코프와 식별자 바인딩을 저장하는 Environment Record를 참조하기 때문이라고 생각한다.
ECMAScript가 버전업을 하면서 Execution Context내부 구조에 크고작은 변화들이 계속 있었는데, Environment Record와 관련된 부분 위주로 간단하게 살펴보자.
Execution Context 내의 주요 컴포넌트this 바인딩LexicalEnvironmentVariableEnvironmentLexicalEnvironment, VariableEnvironment 두 레코드가 같은 참조값을 가진다. (LexicalEnvironment에 VariableEnvironment값을 복사하여 할당)LexicalEnvironment에 반영된다with, catch문을 평가할 때 새로운 Environment Record를 생성해서 Lexical Environment가 갱신된다.LexicalEnvironment를 [[Scope]]로 참조한다 VariableEnvironment를 [[Scope]]로 참조한다 Lexical Environment에서 관리된다LexicalEnvironment 참조를 탐색한다Execution Context 내에 LexicalEnvironment라는 컴포넌트가 있고,
렉시컬 스코프를 구현하기 위한 outer 참조와 Environemnt Record를 가지는 Lexical Environment라는 명세가 따로 있다.
이름이 같아서 햇갈리므로 이 글에서는 띄워쓰기 유무로 구별하겠다.
with문이 있을 때 어떻게 되는지 그림으로 나타내보자.
아래와 같은 코드를 평가하면 foo, bar가 각각 10, 20을 출력한다.
var a = 10;
// FD
function foo() {
console.log(a);
}
with ({a: 20}) {
// FE
var bar = function () {
console.log(a);
};
foo(); // 10!, from VariableEnvrionment
bar(); // 20, from LexicalEnvrionment
}
foo(); // 10
bar(); // still 20
with문 진입 전에는 다음과 같은 상황일 것이다.

with문 진입하여 bar 함수 할당되고 난 후에는 다음처럼 Lexical Environment가 하나 더 추가된 상황일 것이다.

foo 함수는 VariableEnvironment를 스코프로 가지기 때문에 a 값이 10이 되고, bar 함수는 LexicalEnvrionment를 스코프로 가져서 a 값이 20이 된다.this 바인딩이 Environment Record에서 관리된다Function Environment Record타입이 등장하였고, 화살표 함수임을 나타내기 위한 프로퍼티가 추가되었다Execution Context의 LexicalEnvironment, VariableEnvironment 컴포넌트의 역할이 변경되었다VariableEnvironment는 var 식별자의 바인딩을 저장한다LexicalEnvironment는 그 외의 let, const, function 선언의 바인딩을 저장한다LexicalEnvironment가 생성된다.블록 스코프를 가지는 let, const 키워드가 추가되었다. 블록문이 있을 때 어떻게 되는지 예시를 보자.
var a = 1;
function Foo() {
const b = 2;
{
const b = 3;
console.log(a); // 1
console.log(b); // 3
}
}
Foo();
console.log()가 실행될 때의 Execution Context와 Environment를 그려보면 다음처럼 될 것이다.
블록문이 새로운 Lexical Environment를 생성하여 스코프 체인 앞에 추가한 것을 볼 수 있다. 그렇기 때문에 b값이 3으로 출력되는 것이다.

Lexical Environment가 없어지고 하던 역할을 Environment Reocrd가 하게 된다Environment Record의 [[OuterEnv]]에서 상위 스코프를 참조하게 되었다Execution Context에 PrivateEnvironment가 추가되었다일반적인 함수 호출을 하는 경우 다음처럼 구성될 것이다.

그동안 공부하면서 식별자 값을 어떻게 정확하게 찾는지 개인적으로 궁금했었는데 스펙에 기술돼있었다. Execution Context의 ResolveBinding 메소드가 바인딩된 값을 찾는 역할을 한다.
ResolveBinding(name, env?): 식별자 이름과 옵션으로 Environment Record를 매개변수로 받는다. env가 없으면 Running Execution Context의 LexicalEnvrionment를 탐색한다. 탐색하는데 GetIdentifierReference메소드를 호출한다.GetIdentifierReference(env, name, strict): Environment Record의 메소드로 실제로 식별자 바인딩 값을 찾는 역할을 한다. env.[[OuterEnv]] 체인을 타고가면서name의 바인딩을 찾아서 반환한다.자세한 설명은 https://tc39.es/ecma262/#sec-resolvebinding 참조
https://cabulous.medium.com/javascript-execution-context-lexical-environment-and-block-scope-part-3-fc2551c92ce0
https://poiemaweb.com/js-execution-context
https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0
https://meetup.toast.com/posts/129
http://dmitrysoshnikov.com/ecmascript/es5-chapter-3-2-lexical-environments-ecmascript-implementation/#structure-of-execution-context
https://dev.to/luigircruz/javascript-execution-context-38cn
https://262.ecma-international.org/12.0/#sec-execution-contexts
https://262.ecma-international.org/11.0/#sec-execution-contexts
https://262.ecma-international.org/5.1/#sec-10.3
https://tc39.es/ecma262/#sec-execution-contexts
깔끔한 정리 잘보고갑니다.