실행 컨텍스트

Rosevillage·2023년 2월 16일
0

자바스크립트가 동작할 때 나타나는 실행 컨텍스트를 정리해본다
23-10-16 update

실행 컨텍스트(Execution Context)

실행할 코드에 제공할 환경 정보들을 모아놓은 객체

자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는
개념으로 자바스크립트는 동일한 환경에 있는 환경 정보들을 모은 실행 컨텍스트를 콜스택에 쌓은 후 실행해 코드의 환경과 순서를 보장한다.

실행 컨텍스트, 콜 스택

실행 컨텍스트는 아래 조건중 하나를 충족하면 콜스택에 쌓이게 된다.

  • 전역공간은 자동으로 컨텍스트로 구성
  • 함수 실행 시
  • eval() 실행 시

일반적으로는 함수를 이용한 실행 컨텍스트를 사용한다.

다음과 같은 코드가 주어졌을 경우

var str = 'str'; //전역 컨텍스트

function a () { // a 컨텍스트
	function b () { // b 컨텍스트
		console.log(str); // undefined
		str='str2';
		console.log(str); //str2
	}
	a();
	console.log(str) //str
}	
b();
console.log(str) // str

실행 컨텍스트의 스택은 다음과 같은 순서로 실행된다.

자바스크립트 코드가 실행되면,
1. (1)-전역 컨텍스트가 생성되어 콜스택에 쌓이고, 실행된다.
2. (2)-a 함수가 호출되면 컨텍스트가 생성되며, 콜스택에 쌓이고, 실행된다.
3. (3)-a 함수 안에 b 함수가 호출되면 a 함수의 실행이 멈추고 컨텍스트가 생성되며 콜스택에 쌓이고, 실행된다.
4. (4)-b 컨텍스트의 실행이 완료되면 콜스택에서 삭제되고, a 컨텍스트를 중단 시점부터 실행한다.
5. (5)-a 컨텍스트의 실행이 완료되면 콜스택에서 삭제되고, 전역 컨텍스트를 중단 시점부터 실행 후 실행을 완료한다.

이런 방식으로 동작하는 실행 컨텍스트는 다음과 같은 구성요소를 가지고 있다.

실행 컨텍스트 구성

  • VariableEnvironment
    실행 컨텍스트 내에서 VariableStatements에 의해 생성된 바인딩을 보유하는 Environment Record를 식별하는 component
  • LexicalEnvironment
    실행 컨텍스트 내에서 코드에 의해 생성된 식별자 참조를 확인하는 데 사용되는 Environment Record를 식별하는 component

LexicalEnvironment, VariableEnvironment 모두 Environment Record를 지니고 있다.

  • Environment Record :
    ECMAScript 코드의 어휘 중첩 구조를 기반으로 특정 변수 및 함수에 대한 식별자 연결을 정의하는 데 사용되는 타입

    일반적으로 Environment Record는 FunctionDeclaration(함수), BlockStatement(block) 또는 TryStatement의 Catch절과 같은 특정 구문 구조와 연결되며, 코드가 평가될 때마다 해당 코드에 의해 생성된 식별자 바인딩을 기록하기 위해 새로운 Environment Record가 생성된다.

    Environment Record는 [[OuterEnv]]라는 필드를 가지는데 이 필드는 null이나 외부 Environment Record에 대한 참조를 가진다. 이를 통해 Environment Record는 논리적 중첩을 모델링할 수 있게 된다.
    간단히 말해서 외부 변수(부모 실행 컨텍스트의)를 참조 할 수 있게 된다는 의미이다.

LexicalEnvironment

LexicalEnvironment는 실행 컨텍스트 생성 시 수집된 변수 정보를 통해 생성되며,
실행 컨텍스트 내의 코드에서 만든 식별자 참조에 사용되는 Environment Record를 가진다.
LexicalEnvironment는 실행단계에서 Environment Record에 수집된 변수 정보가 코드에 의해서 변경될 수 있다.

  • let, const declarations:
    실행 중인 실행 컨텍스트의 LexicalEnvironment로 범위가 지정된 변수를 정의한다.
    let, const 변수의 선언문과 할당문이 한 줄인 경우 Lexical Binding이 평가될 때 초기 값이 할당된다.

VariableEnvironment

VariableEnvironment는 실행 컨텍스트 생성 시 수집된 변수 정보를 통해 생성되며,
실행 컨텍스트 내에서 VariableStatements에 의해 생성된 바인딩을 보유하는 Environment Record를 가진다.

초기에는 LexicalEnvironment와 동일한 내용으로 구성되어 있지만, 초기 상태의 변수 정보를 유지하는 것이 특징이다.

  • VariableStatements
    var 로 생성된 변수는 실행 중인 실행 컨텍스트의 VariableEnvironment의 Environment Record로 수집되어 범위가 VariableEnvironment로 지정된다. 이때 var 변수는 Environment Record가 인스턴스화 될 때 생성(선언)되고, 생성 시 undefined로 초기화(메모리 공간 확보)된다. 선언문과 할당문이 한 줄인 경우에는 Variable Declaration이 실행될 때, 값이 할당된다.

Block Level Scope와 VariableEnvironment, LexicalEnvironment

우선적으로 다음의 내용은 공식 문서나 공식 스펙에 명시되어 있는 내용은 아니며, 이렇게 해석하는 내용이 다수이기에 소개한ㄷ.
또한 Ecma에서는 공식 스펙은 실행 컨텍스트 개념이 순전히 매커니즘에 불과하다고 안내하고 있다.

  • es6로 넘어오면서 const, let이 추가되고 block level scope 개념이 자바스크립트에 도입되었다.
    알다시피 const, let은 var와 달리 호이스팅 시에 초기화가 진행되지 않으며, block level scope를 따른다.

  • block scope는 외부에서 block 내부로의 접근을 허용하지 않는다. 이는 외부에서는 block 내부를 찾을 수 없다는 것을 의미한다.
    실행 컨텍스트의 생성 조건에는 block이 존재하지 않기 때문에 자바스크립트 엔진은 실행 컨텍스트를 추가해 block을 따로 실행시키지 않는다.

  • 다음과 같은 상황에서 자바스크립트 엔진은 현재 실행 컨텍스트에 block을 위한 임시 LexicalEnvironment를 생성한다.
    이후 실행 컨텍스트는 임시 LexicalEnvironment를 바라보고 임시 LexicalEnvironment는 let, const 변수들을 관리한다.

  • 해당 block이 종료되면, block 이전 스냅샷을 유지하고 있던 VariableEnvironment를 통해 원래 LexicalEnvironment가 가지고 있던 변수들을 복구 한다.

위의 해석에서는 block scope가 외부 변수를 참조할 수 있는 것을 설명하지 못하는 것(?) 같다. 이 내용은 또 추후에 찾아서 정리해본다


23/10/16 추가

ecmascript 2023을 잘펴보던 중 14.2.2 Runtime Semantics: Evaluation 에서 block 이 평가 될때의 과정을 확인했다.

결론적으로 위에서 설명한 내용이 ecma 명세에서 제공하는 내용이며, 이 내용에서 block scope에서 외부 실행 컨텍스트를 어떻게 참조 가능한가에 대한 답을 찾았다. block이 평가되는 과정은 다음과 같다.

  1. 현재 실행중인 context(실행 컨텍스트)의 LexicalEnvironment를 oldEnv로 지정한다.

  2. oldEnv를 NewDeclarativeEnvironment()에 인자로 전달해 새로운 Environment Record를 생성한다. 이를 blockEnv로 지정한다.

    • NewDeclarativeEnvironment는 인수 E(Environment Record 또는 null)를 받아 Declarative Environment Record를 생성한다.
    • 생성된 Environment Record의 [[OuterEnv]]를 E로 지정하고 Environment Record를 반환한다. => (기존 Lexical Environment 참조 가능)
  3. BlockDeclarationInstantiation(StatementList(block 내부 식별자 리스트), blockEnv)를 통해 StatementList를 blockEnv에 바인딩한다.

  4. 실행중인 context의 LexicalEnvironment를 blockEnv로 설정한다.

  5. StatementList의 실행 완료된 값을 blockValue로 지정한다.

  6. 실행중인 context의 LexicalEnvironment를 oldEnv로 지정한다.

  7. blockValue를 반환한다.


참고 사이트

github.io-개발자 황준일-자바스크립트 실행 컨텍스트

velog-요행을 바라지 않는 개발자-edie_ko-실행 컨텍스트란 무엇인가요?

ECMAScript® 2023 language specification

0개의 댓글