본문 바로가기

Programming/JavaScript

[Javascript] Executive context(실행 콘텍스트)

 

1. 실행 콘텍스트란

 

실행 가능한 코드가 실행되기 위해 필요한 환경 정보들을 모아놓은 객체이다. 

 

실행 가능한 코드에는 전역코드, 함수코드, eval()코드가 있다.

 

실행에 필요한 환경 정보

- 변수 (전역변수, 지역변수, 매개변수, 객체의 프로퍼티)

- 함수 선언문

- 변수의 유효 범위(scope)

- This binding 

 

실행 컨텍스트는 스택(stack)의 형태로 되어있어 FILO(First In Last Out)의 프로세스로 작동한다.

 

즉, 가장 최근에 등록된 객체부터 먼저 실행되고 맨 처음에 등록된 객체가 가장 마지막으로 실행된다.

 

2. 실행 콘텍스트에 담기는 정보

다음 설명에서 LexicalEnvironment와 lexical environment라는 단어가 혼용되어 쓰일 것이다. 
(lexical은 어휘의, 사전적인 이라는 의미인데 한글로 번역하여 의미를 해석하기보다 영어 단어 그 자체로 개념을 받아들이는 것이 좋을 것 같다.)
lexical environment는 프로그래밍에서 일반적으로 사용되는 용어이다.
LexicalEnvironment는 lexical environment 자바스크립트에서 실행컨텍스트로 구체적으로 구현한 것이다.

 1) VariableEnvironment

 - Environment Record : 현재 컨텍스트의 식별자들에 대한 정보 (ES3의 Variable Object와 비슷한 개념) 

 → var 변수 + 함수 선언문

 

 - outer-Environment Reference : 외부 환경 정보(스코프 체인)

 → 또 다른 lexical environment 참조(전역 scope + 함수 scope에 대한 정보 포함)

 

선언 시점의 LexicalEnvironment의 스냅샷으로 절대 변하지 않는다.

 

 2) LexicalEnvironmnet

Environment Record : 현재 컨텍스트의 식별자들에 대한 정보 (ES3의 Variable Object와 비슷한 개념) 

 → var 변수 + let/const 변수 + 함수 선언문 + 함수 표현식)

 

 - outer-Environment Reference : 외부 환경 정보(스코프 체인)

 → 또 다른 lexical environment 참조(전역 scope + 함수 scope + 블록 scope 에 대한 정보 포함)

 

 

 

LexicalEnvironment는 초기에는 VariableEnvironmement의 복제본이다.

 

* VariableEnvironment와 LexicalEnvironment의 관계

 

- VariableEnvironment는 LexicalEnvironment의 청사진이다.

즉, LexicalEnvironment는 VariableEnvironment를 기반으로 하여 추가적인 변수와 스코프 정보가 추가된다.

 

- VariableEnvironment는 실행되는 내내 절대 변하지 않는다.

 

3) ThisBinding

 - 전역에 위치한 This의 값은 전역 객체

 - 함수 내부에 위치한 This의 값은 함수 실행 시 결정됨

 

 

4. 실행 콘텍스트의 실행 과정 

 

 

 

 

위와 같은 코드에서 실행 콘텍스트가 어떻게 작동하는지 알아보자.

 

(코드 실행 전)

1) 전역 콘텍스트가 생성되어 콜스택에 쌓인다.

 

이때 전역 콘텍스트에 담기는 정보는

- 식별자 정보: 변수 a, 변수 b, foo() { }

- 외부 환경 정보: 글로벌 객체

- This 값 : 전역 객체

* 전역 객체는 브라우저에서는 window, Node.js 환경에서는 global 객체이다.

 

식별자 정보에는 위와 같이 전역 코드에서 선언된 변수들과 함수 선언문의 정보가 담긴다.

 

변수와 달리 함수 선언문은 함수명과 함수 객체가 함께 담긴 것을 볼 수 있다.

 

이때 전역 콘텍스트 내의 변수 a와 변수 b는 생성 단계가 다른 상태이다.

 

이 차이는 var 키워드로 선언된 변수와 let 키워드로 선언된 변수의 생성이 서로 다르게 작동하기 때문에 나타나는데,

 

 

*우선 변수의 생성 과정을 알아보자.

 

 

 

위 그림은 기본적인 변수의 생성 단계를 나타낸 것이다.

 

 

 

위 그림은 var 키워드로 선언된 변수의 생성 단계이다.

 

var 변수로 선언된 변수는 ①선언단계와 ②초기화단계가 동시에 일어난다.

 

즉, 변수 a는 실행컨텍스트에 담기는 동시에 undefined로 그 값이 초기화된다는 것이다.

 

 

 

위 그림은 let / const 키워드로 선언된 변수의 생성 과정이다.

 

그림에서 알 수 있듯이 모든 단계가 개별적으로 일어난다.

 

현재 let으로 선언된 변수b는 실행컨텍스트에 선언만 되고 초기화는 이루어지지 않은 상태이다.

 

즉, 해당 스코프 내에서 let / const로 선언된 변수의 존재는 인식하고 있지만 그 값은 할당되지 않은 상태인것이다.

 

그래서 지금 상태를 정리해보자면,

 

js파일이 실행되는 동시에 전역 컨텍스트에 식별자정보와 외부 환경 정보와 this 값이 담겼다

→ 식별자 정보에는 선언단계와 초기화단계가 끝난 a 변수와 선언단계만 끝난 b변수와 함수 선언문이 담겨있다.

→ 외부 환경 정보에는 글로벌 객체만 담겨있는 상태이다.

 

2) a 변수에 1이라는 값이 할당된다.

var 로 선언된 a 변수의 생성 단계에서 ③할당단계가 진행되면서 변수의 생성이 완료되었다.

 

3) b 변수에 2라는 값이 할당된다.

let으로 선언된 b 변수의 생성단계에서 ②초기화단계와 ③할당단계가 진행되어 변수의 생성이 완료되었다.

 

12) foo()라는 함수의 실행 콘텍스트가 생성되고 콜스택에 쌓인다.

 

스택 구조의 특성상, 최근에 등록된 foo() 실행콘텍스트가 먼저 실행된다.

 

이때 함수foo()의 실행 콘텍스트에 담기는 정보는 

- 식별자 정보: 변수 b

- 외부 환경 정보: 전역 스코프의 정보

- This 값 : 전역 객체

 

현재 상황에서 let으로 선언된 변수 b는 ①선언단계만 실행된 상태이다.

 

6) a 변수의 값을 찾아 콘솔에 출력한다.

현재 스코프에서는 a의 값을 찾을 수 없다.

 

따라서 외부 환경 정보의 scope chain을 따라 상위 스코프로 a 변수를 찾으러 올라가게 된다.

 

현재 실행 콘텍스트의 상위 스코프인 전역 스코프에는 변수 a의 값이 할당되어있다.

 

따라서 콘솔에는 1이 출력된다.

 

7) b 변수의 값을 찾아 콘솔에 출력한다.

위에서 정리했듯이 let 키워드로 선언된 변수 b는 현재 스코프 내에서 변수의 존재가 인식되기는 했지만 초기화나 할당이 되어있지 않은 상태이다.

 

따라서 콘솔에는 에러가 출력된다.

 

비록 에러가 출력되어 프로그램이 중단되겠지만 에러가 나지 않았다고 가정하고 다음 코드로 넘어가면

 

9) 스코프 내에서 선언만 되어있던 b변수에 5라는 값이 할당된다.

 

10) foo()함수의 실행이 끝나 foo함수 실행 콘텍스트가 콜스택에서 제거된다.

 

12 이후) 더이상 실행할 코드가 없으므로 전역 컨텍스트도 콜스택에서 제거되어 프로그램이 종료된다.

 

call stack 현황 정리

 

 

dmitrysoshnikov.com/ecmascript/es5-chapter-3-2-lexical-environments-ecmascript-implementation/#variable-environment

 

ECMA-262-5 in detail. Chapter 3.2. Lexical environments: ECMAScript implementation.

Read this article in Chinese.

dmitrysoshnikov.com