실행컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아 놓은 객체이다. 실행컨텍스트는 동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 객체를 구성하고 이를 콜 스택에 쌓아 올렸다가 가장 위에 쌓여있는 컨텍스트가 활성화 되는 시점에 선언된 변수를 위로 끌어올리고 외부 환경 정보를 구성하고 this 값을 설정하는 등의 동작을 수행한다. 실행 컨텍스트는 JS의 동적언어로서의 성격을 가장 잘 파악할 수 있는 개념이다. 만약 실행 컨텍스트를 구성하고 싶다면 함수를 실행해보면 된다.
let a = 1;
function outer() {
function inner() {
console.log(a); //Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 3;
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
함수를 실행하면 처음 JS 코드를 실향하는 순간 전역 컨텍스트가 콜 스택에 담기게 된다. 전역 컨텍스트는 코드 내부에서 별도의 실행명령이 없어도 브라우저에서 자동으로 실행하므로 JS파일이 열리는 순간 전역 컨텍스트가 활성화된다고 이해하면 된다. 그러면 콜 스택에서 전역 컨텍스트와 관련된 코드들을 순차로 진행하다가 outer함수를 호출하면 JS 엔진은 Outer에 대한 환경 정보를 수집해서 Outer 실행 컨텍스트를 생성한 후 콜 스택에 담는다. 콜스택의 맨위에 Outer 실행 컨텍스트가 놓인 상태가 되었으므로 전역 컨텍스트와 관련된 코드의 실행을 일시 중단하고 대신 Outer실행 컨텍스트와 관련된 코드 즉, Outer 함수 내부의 코드들을 순차로 실행한다.
그리고 Inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담기면 Outer 컨텍스트와 관련된 코드의 실행을 중단하고 Inner 함수 내부의 코드를 순서대로 진행할 것이다.
Inner함수 내부에서 a변수의 값을 출력하고 나면 Inner 함수의 실행이 종료되면서 Inner 실행 컨텍스트가 콜 스텍에서 제거된다. 그러면 아래 있던 Outer 컨텍스트가 콜 스택의 맨 위에 존재하게 되므로 중단했던 부분인 console.log(a)를 이어서 실행한다. a변수의 값을 출력하고 나면 전역 공간에 더는 실행할 코드가 남아 잇지 않아 전역 컨텍스트도 제거되고 콜 스택에는 남지 않은 상태로 종료되게 된다.
위의 스택 구조를 잘 생각해보면 한 실행 컨텍스트가 콜 스택의 맨위에 쌓이는 순간이 곧 현재 실행할 코드에 관여하게 되는 시점임을 알 수 있다. 이렇게 어떤 실행 컨텍스트가 활성화 될 때 JS엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집해서 실행컨텍스트 객체에서 저장하는데 여기에 담기는 정보들은 아래와 같다.
VariableEnvironment : 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보. 선언시점의 LexicalEnvironment의 스냅샷으로, 변경 사항은 반영되지 않음
LexicalEnvironment : 처음에는 VariableEnvironment와 같지만 변경 사항이 실시간으로 반영됨.
ThisBinding : this 식별자가 바라봐야 할 대상 객체