Javascript

실행 컨텍스트

muyeon 2023. 12. 26. 18:43

실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.

이는 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념이다.

 

자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고(호이스팅), 외부 환경 정보를 구성하고 this 값을 설정하는 등의 동작을 수행하는데, 이로 인해 다른 언어에서는 없는 특이한 현상이 발생한다.

 

클로저를 지원하는 대부분의 언어에서 이와 유사하거나 동일한 개념이 적용되어 있다.

 

실행 컨텍스트란?

 

실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다. 

동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고 이를 콜 스택에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장한다.

 

하나의 실행 컨텍스트를 구성할 수 있는 방법은 전역공간, eval 함수, 함수 등이 있다. 흔히 실행 컨텍스트를 구성하는 방법은 보통 함수를 실행하는 것 뿐이다.

 

// (1)
var a = 1;

function outer() {
	function inner() {
    	console.log(a) // undefined
        var a = 3
    }
    inner(); // (2)
    console.log(a); // 1
}

outer(); // (3)
console.log(a); // 1

(1) 처음 자바스크립트 코드를 실행하는 순간 전역 컨텍스트가 콜스택에 담긴다.

(전역 컨텍스트는 일반적인 실행 컨텍스트와 특별히 다를 것이 없다. 차이점은 외부스코프가 존재하지 않기때문에 전역스코프 하나만 존재하고 전역공간이기에 arguments 가 없다.)

최상단의 공간은 코드 내부에서 별도의 실행 명령이 없어도 브라우저에서 자동 실행하므로 자바스크립트 파일이 열리는 순간 전역 컨텍스트가 활성화된다고 생각하면 된다.

 

콜 스택에는 전역 컨텍스트 외에 다른 덩어리가 없으므로 전역 컨텍스트와 관련된 코드들을 순차로 진행하다가 (3)에서 outer 함수를 호출해 자바스크립트 엔진은 outer 에 대한 환경 정보를 수집해 outer 실행 컨텍스트를 생성한 후 콜 스택에 담는다.

콜 스택 맨 위에 outer 실행 컨텍스트가 놓인 상태가 되었으므로 전역 컨텍스트와 관련된 코드의 실행을 일시 중단하고 대신 outer 실행 컨텍스트와 관련된 코드, 즉 outer 함수 내부의 코드들을 순차로 실행한다.

 

(2)에서 inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행한다.

 

inner 함수 내부에서 a 변수에 값 3을 할당하고 나면 inner 함수의 실행이 종료되면서 inner 실행 컨텍스트가 콜 스택에서 제거된다.

그러면 아래에 있던 outer 컨텍스트가 콜 스택의 맨 위에 존재하게 되므로 중단되었던 (2)의 다음줄 부터 이어서 실행한다. 

 

a 변수의 값을 출력하고 나면 outer 함수의 실행이 종료되어 outer 실행 컨텍스트가 콜 스택에서 제거되고, 콜 스택에는 전역 컨텍스트만 남아 있게 된다.

 

그 다음 실행 중단되었던 (3)의 다음 줄 부터 이어서 실행한다. a 변수의 값을 출력하고 나면 전역 공간에 더는 실행할 코드가 남아 있지 않아 전역 컨텍스트도 제거되고, 콜 스택에는 아무것도 남지 않은 상태로 종료된다.

 

스택 구조를 보면 한 실행 컨텍스트가 콜 스택의 맨 위에 쌓이는 순간이 현재 실행할 코드에 관여하게 되는 시점이다.

어떤 실행 컨텍스트가 활성화될때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장한다. 이 객체는 자바스크립트 엔진이 활용할 목적으로 생성할 뿐 개발자가 코드를 통해 확인 할 수 없다.

 

실행 컨텍스트 객체에 담기는 정보는 다음과 같다.

 

  •  Variable Environment : 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보, 선언 시점의 Lexical Environment의 스냅샷으로 변경사항은 반영되지 않음.
  •  Lexical Environment : 처음에는 Variable Environment 와 같지만 변경 사항이 실시간으로 반영된다.
  •  This Binding : 식별자가 바라봐야 할 대상 객체

 


Variable Environment

 

VariableEnvironment 에 담기는 내용은 LexicalEnvironment 와 같지만 최초 실행 시의 스냅샷을 유지한다는 점이 다르다.

실행 컨텍스트를 생성할 때 VariableEnvironment에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LexicalEnvironment를 만들고 이후에는 LexicalEnvironment를 주로 활용하게 된다.

 

VariableEnvironment 와 LexicalEnvironment 의 내부는 environmentRecord 와 outer-EnvironmentReference 로 구성되어 있다. 

초기화 과정 중에는 사실상 완전히 동일하고 이후 코드 진행에 따라 서로 달라지게 될 것이다.

 


Lexical Environment

 

LexicalEnvironment 에 대한 한국어 번역은 문사마다 다른데, '어휘적 환경', '정적 환경' 이라는 단어가 가장 많이 등장한다.

이러한 말보다는 '사전적인' 이 더욱 어울리는 표현이다.

"현재 실행 컨텍스트 내부에는 a, b, c 와 같은 식별자들이 있고 그 외부 정보는 d 를 참조하도록 구성되어 있다." 라는 컨텍스트를 구성하는 환경 정보들을 사전에서 접하는 느낌으로 모아 놓은 것이다.

 


environmentRecord & 호이스팅

 

environmentRecord 에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장된다.

컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우 그 함수 자체, var 로 선언된 변수의 식별자 등이 해당된다.

컨텍스트 내부 전체를 처음부터 끝까지 훑어 순서대로 수집한다.

 

변수 정보를 수집하는 과정을 모두 마쳤더라도 실행 컨텍스트가 관여할 코드들은 실행되기 전의 상태이다. 코드가 실행되기 전임에도 불구하고 자바스크립트 엔진은 이미 해당 환경에 속한 코드의 변수명들을 모두 알고 있게 된다.

 

즉, 자바스크립트 엔진은 식별자들을 최상단으로 끌어올려 놓은 다음 실제 코드를 실행한다라고 생각하더라도 코드를 해석하는데에는 문제가 없다.

 

이 개념이 호이스팅이다. 이는 끌어올리다라는 의미의 hoist + ing 를 붙인 것이고, 변수 정보를 수집하는 과정을 이해하기 쉬운 방법으로 대체한 가상의 개념이다. 자바스크립트 엔진이 실제로 끌어올리지는 않지만 편의상 끌어올린 것으로 간주하는 것이다.

 


마무리

 

다음 글에서는 호이스팅에 대해서 다뤄보도록 하겠다.