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

ma.caron_g·2022년 12월 20일
0

Java Script

목록 보기
10/11
post-thumbnail

< 참고 링크 >

[ Execution Context ]

실행 컨텍스트(execution Context)는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체로, 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념입니다.

  • 정재남, 코어 자바스크립트

실행 컨텍스트는 자바스크립트 코드가 실행되는 환경입니다.

모든 JavaScript 코드는 실행 컨텍스트 내부에서 실행된다고 생각하면 됩니다.

즉, 함수가 실행되면 함수 실행에 해당하는 실행 컨텍스트가 생성되고, 자바스크립트 엔진에 있는 콜 스택에 차곡차곡 쌓입니다.

그리고 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드를 실행하면서(LIFO), 전체 코드의 환경과 순서를 보장하게 됩니다.
실행 컨텍스트는 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드
실행 순서 관리를 구현한 내부 매커니즘으로, 실행 컨텍스트는 곧 자바스크립트의 핵심원리입니다.

const first = () => {
    console.log('첫 번째');
    second();
    console.log('세 번째');
}

const second = () => {
    console.log('두 번째');
}

first()

[ 실행 컨텍스트의 생성 시기 ]

자바스크립트 엔진이 스크립트를 처음 마주할 때 전역 컨텍스트를 생성하고, 콜 스택에 push합니다.

엔진이 스크립트를 쭉 읽어내려가면서 함수 호출을 발견할 때마다, 함수의 실행 컨텍스트를 스택에 push합니다.

중요한 점은 함수 실행 컨텍스트는 함수가 실행될 때 만들어진다는 점입니다.

함수를 선언할 때가 아니라 실행할 때입니다.

실행 컨텍스트를 만들 수 있는 방법으로는 1) 전역공간, 2) 함수, 3) eval() 함수가 있습니다.
(3. eval()은 구글 스타일 가이드에서 사용하지말라 함.)

실행 컨텍스트가 실행되는 시점은 곧 함수를 실행하는 시점입니다.

[ 실행 컨텍스트의 종류 ]

실행 컨텍스트는 LexicalEnvironment 컴포넌트와 varialbleEnvironment 컴포넌트로 구성됩니다.

함수가 호출되면 전역 공간에 있던 코드의 제어권이 함수의 내부로 이동하면서 함수 코드를 평가하기 시작합니다.

함수 코드 평가 순서는 다음과 같이 진행됩니다.

1) 함수 실행 컨텍스트 실행
2) 함수 LexicalEnvironment 생성
2-1) 함수 environmentRecord 생성
2-2) ThisBinding
2-3) outerEnvironmentReference 결정

각 요소들의 정보는

  • variableEnvironment : 현재 컨텍스트 내의 식별자에 대한 정보 + 외부 환경 정보를 담습니다.
    선언 시점의 LexicalEnvironment의 스냅샷으로 변경 사항은 반영되지 않습니다.
    실행 컨텍스트를 생성할 때 variableEnvironment에 정보를 먼저 담은 다음, 이를 복사해서 LexicalEnvironment`를 만듭니다.

    • environmentRecord (snapshot)
    • outerEnvironmentReference (snapshot)
  • LexicalEnvironment(어휘적 환경): 처음에 variableEnvironment와 같지만 변경사항이 실시간으로 반영됩니다.

    • environmentRecord(환경 레코드): 함수 안의 코드가 실행되기 전에 현재 컨텍스트와 관련된 코드의 식별자 정보가 저장됩니다. (매개변수의 이름, 함수 선언, 변수명 등)
      즉, 코드가 실행되기 전에 자바스크립트 엔진은 이미 해당 환경에 속한 코드의 변수명을 모두 알고 있게 됩니다. (호이스팅)
    • outerEnvironmentReference(외부 렉시컬 환경에 대한 참조) : 상위 스코프를 가리킵니다.
      즉, 현재 environmentRecord보다 바깥에 있는 environmentRecord를 참고한다는 뜻이며 해당 실행 컨텍스트를 생성한 함수의 바깥 환경을 가리킵니다.
      따라서 자바스크립트 엔진이 현재 렉시컬 환경에서 변수를 찾을 수 없다면 외부 환경에서 찾는다는 것을 뜻합니다.
      만약, 상위 스코프에서 해당 식별자를 찾을 수 없다면 참조 에러(uncaught reference error)가 발생합니다.
  • ThisBinding: this 식별자가 바라봐야 할 대상 객체.
    실행 컨텍스트가 활성될 때 this가 지정되지 않은 경우 this에는 전역 객체가 저장됩니다.

LexcialEnvironment 렉시컬 환경 (어휘적 환경)

렉시컬 환경은 식별자와 식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트이다.
실행 컨텍스트 스택이 코드의 실행 순서를 관리한다면, 렉시컬 환경은 스코프와 식별자를 관리합니다.
렉시컬 환경은 키와 값을 갖는 객체 형태의 스코프를 생성해서 식별자를 키로 등록하고 식별자에 대한 바인딩된 값을 관리합니다.

[ 실행 컨텍스트의 생성과 작동 과정 ]

코드를 보며 실행 컨텍스트의 생성과 식별자 검색 과정을 알아보겠습니다.

1 const str = '안녕';
2
3 function outer() {
4   function ineer() {
5     const greeting = '하이';
6     console.log(greeting);
7     console.log(str);
8    }
9    inner();
10 }
11 outer();
12
13 console.log(str);
  1. 시작: 전역 컨텍스트가 생성됩니다.
    전역 컨텍스트에 environmentRecord{str, outer} 식별자가 저장됩니다.
    전역 컨텍스트는 가장 최상위 컨텍스트이므로 outerEnvironmentRefernce는 null값을 가집니다. (this: 전역객체)

  2. Line1,3 : 전역 스코프에 있는 변수 str에 '안녕'을, outer에 함수를 할당합니다.

  3. Line11 : outer를 호출합니다.
    전역 컨텍스트의 코드는 11번 째 줄에서 잠시 중단되고, outer 실행 컨텍스트가 활성화되어 3번 째로 이동합니다.

  4. Line3 : outer 실행 컨텍스트의 environmentRecord{ inner } 식별자를 저장합니다.
    outerEnvironmentReference에는 outer 함수가 선언될 당시의 LexicalEnvironment가 담깁니다.
    (=== 전역 컨텍스트의 LexicalEnvironment).
    이를 { GLOBAL, {a, outer }}라고 표기합니다. 첫 번째는 실행 컨텍스트의 이름, 두 번째는 environmentRecord의 객체입니다. (this: 전역객체 )

  5. Line4 : outer 스코프에 있는 변수 inner에 함수를 할당합니다.

  6. Line8 : inner 함수를 호출합니다. 여기서 outer실행 컨텍스트의 코드는 임시 중단되고, inner 함수를 호출합니다. inner 실행 컨텍스트가 활성되어 4번 째 줄로 이동합니다.

  7. Line5 : inner 실행 컨텍스트의 environmentRecord{ greeting } 식별자를 저장합니다.
    outerEnvironmentReferenceinner함수가 선언될 당시에 LexicalEnvironment가 담깁니다.
    inner함수는 outer함수에서 선언되었으므로 outer 함수의 LexicalEnvironment, 즉, { outer, { inner }}를 참조 복사합니다. (this: 전역 객체 )

  8. Line6 : environmentRecord에 있는 greeting을 찾아서 실행합니다.

  9. Line7 : 식별자 str에 접근하려고 합니다. 이때 자바스크립트 엔진은 활성화된 실행 컨텍스트의 LexicalEnvironmentReference에 있는 environmentRecord로 넘어가는 식으로 계속해서 검색합니다.
    여기서 전역 LexicalEnvironmentstr이 있으므로 '안녕'을 출력합니다.

  10. Line8 : inner 함수 실행이 종료됩니다. inner 실행 컨텍스트가 콜 스택에서 제거되고, outer 실행 컨텍스트가 다시 활성화되면서 9번째 줄로 이동합니다.

  11. Line10 : outer함수 실행이 종료됩니다. outer 실행 컨텍스트가 콜 스택에서 제거되고, 전역 컨텍스트가 다시 활성화됩니다.

  12. Line13 : 전역 컨텍스트의 environmentRecord에서 str을 검색해서 실행합니다.

  13. 완료 : 모든 코드의 실행이 종료되어 전역 컨텍스트가 콜 스택에서 제거되고 종료됩니다.

profile
다른 사람이 만든 것을 소비하는 활동보다, 내가 생산적인 활동을 하는 시간이 더 많도록 생활화 하자.

0개의 댓글