개발/Javascript

[Javascript] Execution Context (실행 컨텍스트)

이나당 2022. 9. 2. 08:27

실행 컨텍스트란?

- 자바스크립트의 동작 원리를 담고 있는 핵심 개념. 자바스크립트가 실행되기 위한 환경 정보들이 모여있다.
- 실행 컨텍스트는 실행하는데 필요한 환경을 제공한다.
- 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행순서 관리를 구현한 내부 메커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.





ECMAScript 사양은 소스코드(ECMAScript code)를 4가지 타입으로 구분한다.
이 4가지 타입의 소스코드는 실행 컨텍스트를 생성한다.

소스코드 타입 설명
전역 코드
global code
- 전역에 존재하는 소스코드 (default, 함수 내부에 있지않는코드)
- 전역 변수를 관리하기위해 최상의 스코프인 전역 스코프 생성 (create global object... window object)
- 전역에 정의된 함수, 클래스 등의 내부 코드는 포함되지 않음
- this값을 global object와 일치시킴
- 프로그램에는 하나의 global Execution만 존재한다
함수 코드
function code
- 함수 내부에 존재하는 소스코드. 모든 함수가 호출될 때 생성됨
- 지역스코프를생성 후 지역변수, 매개변수, 인자 객체를 관리하며 전역스코프에서 시작하는 스코프 체인의 일원으로 연결해야 함
- 함수마다 각자의 실행 컨텍스트 보유
- 함수 내부에 중첩된 함수, 클래스 등의 내부 코드는 포함되지 않음
eval 코드
eval code
- 빌트인 전역 함수인 eval 함수에 인수로 전달되어 실행되는 소스코드
- strict mode에서 자신만의 독자적인 스코프를 생성
- eval코드가 평가되면 eval 실행 컨텍스트가 생성된다
모듈 코드
module code
- 모듈 내부에 존재하는 소스코드
- 모듈 내부의 함수, 클래스등의 내부 코드는 포함되지 않음

소스코드(실행가능한 코드)를 타입으로 구분하는 이유는 소스코드 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리내용이 다르기 때문이다.



소스코드의 평가와 실행

자바스크립트 엔진은 소스코드를 평가와 실행 과정으로 나누어 처리한다.
소스코드 평가 과정에서는 실행 컨텍스트를 생성하고 변수, 함수 등의 선언문만 먼저 실행하여 생성된 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(Lexical environment)에 등록한다
소스코드 평가 후 선언문을 제외한 소스코드가 실행된다. 이를 런타임이 진행된다고 한다. 이 때, 소스코드 실행에 필요한 변수나 함수의 참조를 실행 컨텍스트가 관리하는 스코프에서 검색 후 취득한다.
변수 값의 변경등 소스코드의 실행 결과는 다시 실행 컨텍스트가 관리하는 스코프에 등록된다.


var x;
x = 1;


위 코드를 JS엔진은 2개의 과정으로 나누어 처리한다.


먼저 소스코드 평가 과정에서 선언된 var x;를 실행하고, 생성된 변수 식별자 x는 실행컨텍스트가 관리하는 스코프에 등록되어 undefined로 초기화 된다.
평가 과정이 끝나면 비로소 소스코드 실행이 시작되고. 이미 평가과정에서 실행된 var x; 가아닌 x = 1;만 소스코드 실행과정에서 실행된다.
이때 변수에 값을 할당하려면 먼저 x 변수가 선언된 변수인지 확인하고 선언된 변수라면 값을 할당한다.

실행 컨텍스트 스택

const x = 1;

function foo(){
    const y = 2;

    function bar(){
        const z = 3;
        console.log(x + y + z);
    }
    bar();
}

foo();

위 전역코드와 함수코드로 이루어진 예제를 살펴보자.


자바스크립트 엔진은 먼저 전역코드를 평가하여 전역 실행컨텍스트를 생성 후 함수가 호출되면 함수코드를 평가하여 함수 실행컨텍스트를 생성한다.

이 때 생성된 실행 컨텍스트는 스택자료구조로 관리된다. 이를 실행컨텍스트 스택 이라고 부른다

이렇게 실행 컨텍스트 스택은 코드의 실행 순서를 관리한다. 그리고 실행컨텍스트 스택의 최상위에 존재하는 실행 컨텍스트는 언제나 현재 실행중인 코드의 실행 컨텍스트이다.




렉시컬 환경 (Lexical Environment)

- 키와 값을 갖는 객체형태의 스코프(전역, 함수, 블록 스코프)를 생성하여 식별자를 키로 등록하고 식별자에 바인딩 된 값을 관리한다. 즉, 렉시컬 환경은 스코프를 구분하여 식별자를 등록하고 관리하는 저장소 역할을 하는 렉시컬 스코프의 실체


생성 초기에 LexicalEnvironment 컴포넌트와 VariableEnvironment 컴포넌트는 하나의 동일한 렉시컬 환경을 참조한다. ThisBinding을 제외한 두 환경 컴포넌트는 현재 컨텍스트 내의 식별자들에 대한 정보와 외부 환경 정보가 담기게된다. Lexical Environment는 자바스크립트 코드에서 변수나 함수 등의 식별자를 정의하는데 사용하는 객체, Environment Record는 식별자들의 바인딩을 기록하는 객체(변수, 함수 등이 기록되는 장소)로 세분 된다.

렉시컬 스코프에서 자바스크립트는 함수를 어디서 호출했는지가 아닌 어디서 정의했는지에 따라 상위스코프를 결정하며, 함수 객체는 자신이 정의된 스코프, 즉 상위스코프를 기억한다.

또한 ES6이전에는 전역 객체가 전역 환경 레코드의 역할을 수행했다. 그러나 ES6 let, const 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 되지 않고 개념적인 블록 내에 존재하기 때문에 이를 관리하기위한 전역 스코프 역할을 하는 전역 환경 레코드는 객제 환경 레코드(Object Environment Record)와 선언적 환경 레코드(Declarative Environment Record)로 구성되어있다.




var x = 1;
const y = 2;

function foo(a) {
...

객체 환경 레코드 : 기존의 전역 객체가 관리하던 var 키워드로 선언한 전역변수와 함수 선언문으로 정의한 전역함수, 빌트인 전역 프로퍼티와 빌트인 전역함수, 표준 빌트인 객체 관리
선언 환경 레코드 : let, const 키워드로 선언한 전역변수 관리

var 키워드는 선언과 동시에 초기화 되어 undefined
let, const는 선언단계와 초기화 단계가 분리되어있다. 초기화 단계, 즉 런타임에 실행 흐름이 변수 선언문에 도달하기 전까지 uninitialized인 일시적 사각지대(Temporal Dead Zond; TDZ)에 빠져있다




환경 레코드 생성구성 이후 외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference)는 현재 평가중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경, 즉 상위 스코프를 가리키며, 이를 통해 단방향 링크드 리스트인 스코프 체인을 구현한다





뭔가 할수록 더 헷갈려 지는것같다.
일단은 실행 컨텍스트전에 소스코드의 평가가 이루어진다는 점과 실행컨텍스트의 스택은 기억해두자.
다음장이 스코프니까.. 스코프를 파헤쳐 보면서 렉시컬 환경은 다시보도록 하자.






어려워!





참고 :
- 모던자바스크립트 Deep Dive (이웅모), 위키북스
- https://www.youtube.com/watch?v=EWfujNzSUmw

반응형