실행 컨텍스트는 Javascript 엔진이 코드를 실행하고 평가(표현식 해석, 값 생성 및 참조)하기 위해 필요한 환경을 제공하고 코드 실행 결과를 실제로 관리하는 영역이다. 이런 실행 컨텍스트를 기반으로 식별자, 스코프 등을 관리한다.
실행 컨텍스트(Execution Context)
Context(컨텍스트)를 번역하면 '문맥'이라는 뜻이다. 이런 뜻을 바탕으로 생각해보면 Javascript의 실행 컨텍스트는 '코드의 문맥', 즉 코드가 실행되는 환경이라고 이해하면 좀 더 쉬울 것 같다. 실행 컨텍스트는 이러한 환경에서 실행될 코드들에 대한 온갖 정보를 모아둔 객체이다. 이렇게 정보를 모아 저장해둔 덕분에 코드가 여러 번 실행되어도 동일한 환경을 구성할 수 있게 되는 것이다.
일단 실행 컨텍스트의 대표적인 유형들이다. 기본이 되는 전역 컨텍스트라는게 있고, 어떤 함수가 호출될 때마다 생성되는 함수 실행 컨텍스트라는 게 있구나 정도만 알고 넘어가자!
✔️ Global Execution Context
실행 컨텍스트의 가장 기본이라 할 수 있는 전역 컨텍스트이다. 코드가 특정한 함수 안에서 실행되는게 아니라면, 그 코드의 컨텍스트는 전역 컨텍스트라고 보면 된다.
✔️ Functional Execution Context
함수가 호출될 때마다 해당 함수에 대해 생성되는 실행 컨텍스트이다. 실행 컨텍스트는 함수가 호출이 되어야 만들어지며, 각 함수들은 자신만의 실행 컨텍스트를 가진다.
✔️ Eval Function Execution Context
문자로 표현된 코드를 실행하는 'eval()'이라는 함수도 자신만의 실행 컨텍스트를 가지는데, 'eval() is evil'이라는 말이 있을 정도로 사용을 지양하기 때문에 설명하지 않으려고 한다. 궁금하다면 관련 문서를 한번 보길,,
계속 언급했듯이 실행 컨텍스트는 코드가 실행되는 범위에 대한 개념이다. Javascript에서 어떤 코드가 실행 중이라는 것은 그 코드가 실행되는 환경인 '실행 컨텍스트'가 활성화 되었음을 의미한다. 이렇게 어떤 실행 컨텍스트가 활성화되면, Javascript엔진은 그 환경과 관련된 정보들을 수집해 실행 컨텍스트 객체에 저장한다.
이 정보들은 스택(Stack)처럼 차곡차곡 저장되는데, 우선 한번 코드와 그림을 통해 어떻게 뭐가 어디에 쌓인다는 것인지 눈으로 확인해보자.
1) 우선 가장 처음 코드가 실행되면, 별도의 명령없이 최상단 부분의 정보가 '전역 컨텍스트'에 저장되고, 이렇게 형성된 전역 컨텍스트 객체가 스택에 가장 먼저 쌓이게 된다. 변수를 선언하거나, 함수선언식이 있는 부분이 이에 해당한다.
2) 그렇게 전역 정보 수집이 끝나고 차례로 코드가 진행되다가, func1 함수가 호출되는 부분에서 Javascript 엔진은 이전(전역)의 정보수집을 마치고 새로운 수집을 시작한다. 이번에는 func1 함수의 실행컨텍스트를 수집하는 것이다. 이번에도 마찬가지로 관련된 환경의 모든 정보를 수집한 후, 형성된 fun1 실행 컨텍스트 객체를 스택에 저장한다. 이제 스택은 전역컨텍스트, fun1 실행 컨텍스트 이렇게 두개가 쌓여있는 모습을 하게 되었다.
3) func1의 정보 수집을 하다가 또 다시 func2가 호출되는 부분에서 이전(func1)의 정보수집을 마치고 새로운 수집을 시작한다. 예상했듯 이번에는 func2 함수의 환경정보를 수집하게 된다.
이처럼 스택에 실행 컨텍스트들이 차곡 차곡 쌓이게 된다. 이렇게 쌓인 것들은 함수가 종료될 때 자신을 호출한 실행 컨텍스트에 반환되며 스택에서 빠지게 된다.
✔️ 어떤 코드가 실행된다 = 실행 컨텍스트가 활성화된다 ⇒ Javascript 엔진이 해당 컨텍스트 관련 정보들을 수집 ⇒ 실행 컨텍스트 객체에 저장
수집되는 정보들 📝
이제 실행 컨텍스트가 활성화되면, 환경 정보가 Javascript 엔진에 의해 수집되어 실행 컨텍스트 객체에 저장된다는 것을 알게 되었다. 그렇다면 대체 어떤 정보들이 수집된다는 것일까? 정보는 Javascript 엔진이 자기가 코드들을 실행시키는 데 쓰려는 목적으로 알아서(?) 수집하는 것이기 때문에 코드로 따로 확인하는 것은 불가능하다. 일단 아까 스택에 쌓였던 func2의 실행 컨텍스트 객체를 한번 확대해서 자세히 살펴보자.
✔️ VariableEnvironment
1) environmentRecord
2) outerEnvironmentReference
VariableEnvironment에 담긴 정보의 내용은 아래 LexicalEnvironment와 동일하기 때문에 여기서는 설명을 생략하고 넘어가려 한다. 단지 VariableEnvironment는 실행 컨텍스트가 처음 생성될 때 정보가 담기는 곳이고, 이를 복사해 만들어진 LexicalEnvironment는 그 후에 변동사항이 있을 때 생성되는 곳이라는 차이 정도만 알고 다음 설명으로 넘어가자!
✔️ LexicalEnvironment
1) environmentRecord
현재 컨텍스트와 관련된 코드 식별자 정보들이 처음부터 차례대로 저장된다. 예를들어 매개변수명, 함수선언, 변수명 등이 여기에 포함된다. Javascript엔진은 이처럼 코드 실행 전에 정보들을 먼저 수집하는데, 바로 이 과정이 '호이스팅(hoisting)'이다. 식별자 정보들이 먼저 수집되기 때문에, 맨 윗부분으로 끌어올린듯한 효과를 낸다고 해서 붙여진 이름이다. 호이스팅 더 알아보기
2) outerEnvironmentReference
outer(외부) + environment(환경) + reference(참조) 말 그대로 외부환경에 대한 참조 정보가 저장된다. 각 outerEnvironmentReference는 각자 자기가 선언되었던 당시의LexicalEnvionment를 참조한다. 아래 그림을 통해서도 볼 수 있듯이 연결리스트의 형태를 띠게 된다. 계속 참조를 타고 올라가다보면 그 끝에는 전역 컨텍스트의 LexicalEnvironment가 나오게 될 것이다. 추가로 가장 가까운 요소부터 차례로만 접근이 가능하며, 순서가 뒤바뀌면 안된다!
outerEnvionmentReference는 이처럼 가까운 요소끼리 연결된 형태로 참조를 하기 때문에 '스코프 체인'도 가능하게 해준다. 스코프 체인이란 스코프를 안 ⇒ 밖 방향으로 차례로 검색하는 것을 말한다. 스코프 더 알아보기
✔️ ThisBinding
this로 지정된 객체를 저장하며, this가 따로 지정되지 않은 경우에는 전역객체를 저장한다. (이 부분은 this의 개념을 다루는 글을 먼저 보고오는 것을 추천한다)
요약
Javascript 엔진은 최초로 코드가 실행되거나, 어떤 함수가 호출될 때 해당 컨텍스트(맥락, 환경)와 관련된 정보들을 수집한다. 그리고 이 정보들을 실행 컨텍스트 객체에 저장한다. 저장되는 정보들에는 어떤 것이 있었을까? 우선 최초로 수집되는 정보는 VariableEnvironment에 담기고, 이후 변경사항이 생기면 이를 복사한 LexicalEnvionment가 생성되어 변경된 정보가 담긴다. Variable, Lexical 모두에 포함되는 environmentRecord에는 현재 컨텍스트와 관련된 코드 식별자 정보들(매개변수명, 함수선언, 변수명)이 처음부터 차례대로 저장되며 outerEnvironmentReference에는 자기가 선언되었던 당시 참조했던 LexicalEnvionment의 정보가 저장된다. 마지막으로 ThisBinding은 this로 지정된 객체를 저장하며, this가 따로 지정되지 않은 경우에는 전역객체를 저장한다.
'Language > Javascript' 카테고리의 다른 글
OOP (1) 객체지향 프로그래밍, 클래스 (0) | 2021.01.14 |
---|---|
this(1) 상황따라 바뀌는 this (0) | 2021.01.14 |
undefined 제대로 알기 (2) null의 등장 (0) | 2021.01.10 |
undefined 제대로 알기 (1) undefined? empty? 🧐 (0) | 2021.01.10 |
ES6 주요 문법 정리 (2) let/const, Iterators, Generators, Unicode, Modules (0) | 2021.01.08 |
댓글