[Javascript] 2. Execution Context (Part 2)

박정민·2022년 8월 30일
0

JavaScript

목록 보기
3/3
post-thumbnail

Execution Context의 구성

  1. Lexical Environment : 식별자와 스코프 관리
  2. Execution Context Stack (Call Stack) : 코드 실행 순서 관리

Execution Context Stack : Code의 실행 순서 관리

코드가 실행되는 순서에 따라 Execution Context가 stack에 push, pop하면서 코드 실행 순서를 관리한다.

  1. Global code
    • JS Engine은 Global code를 평가하고 이로부터 global execution context를 생성해 Stack에 push한다.
    • 이 때 Global scope에 해당되는 property, method들은 global execution context에 등록된다. 따라서 Stack에 global scope에 해당되는 entity들이 stack에 같이 들어가있다.
  2. function call
    • 함수 호출 시 global code의 흐름을 멈추고 호출된 함수 내부로 이동된다. (코드의 제어권 이동)
    • JS Engine은 function code를 평가해 function execution context를 생성하고 execution context stack에 push한다.
    • 만일 함수 내에 다른 함수가 정의되어 있는 형태라면 해당 함수도 똑같이 평가, push 등의 작업이 이루어진다.
  3. function end
    • 함수 종료 시 코드의 제어권을 상위 스코프로 넘기고 JS Engine에 의해 execution context stack에서 해당 함수의 execution context가 pop된다.
  4. end
    • Stack 내부에서 Global execution context 위에 쌓여있던 context들이 모두 실행이 완료되면 global code로 돌아온다.
    • global code의 실행이 종료되면 global execution context도 call stack에서 pop되어 execution context는 empty상태가 된다.

따라서 Execution context stack은 코드의 실행 순서를 관리한다.
또한 stack의 top은 항상 현재 실행중인 코드의 execution context이다.
Running Execution Context : execution context stack의 top에 위치한 execution context

Lexical Environment : Scope, Identifier 관리

  • Lexical Environment
    - Execution context를 구성하는 component

    • 식별자와 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 기록하는 자료구조
      - key, value를 갖는 객체 형태의 스코프를 생성해 identifier를 key로 등록하고 바인딩된 값을 관리
      -> Lexical scope의 실체
      - lexical scope? : scope를 구분해 identifier를 등록하고 관리하는 저장소
  • Execution context : Lexical Environment Component와 Variable Environment Component으로 구성

  • 생성 초기에 Lexical Environment Component와 Variable Environment Component는 동일한 lexical environment를 참조하지만 상황에 따라 Variable Environment를 위한 새로운 lexical 환경이 생성되는 등 두 component의 내용이 달라질 수 있음

Lexical Environment의 구성요소

  1. Environment Record
    • Scope에 포함된 식별자를 등록하고, 등록된 식별자에 바인딩된 값을 관리하는 저장소
    • source code type에 따라 관리 내용이 다름
  2. Outer Lexical Environment Reference
    • 외부 렉시컬 환경의 참조는 상위 스코프를 가리킴 (해당 execution context를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경)
    • Outer Lexical Environment Reference를 통해 단방향 연결 리스트 구조를 가진 스코프 체인 구현

Execution Context의 생성과 Identifier 검색 과정

  1. Global Object 생성
    • Global code 평가 전에 생성
    • Built-in 전역 프로퍼티와 전역 함수, 표준 빌트인 객체 추가
    • Web API 또는 특정 환경을 위한 host 객체 포함
  2. Global Code 평가 : 소스 코드가 로드되면 JS Engine에 의해 전역 코드가 평가
    1. Global Execution context 생성
    2. Global Lexical Environment 생성
      • Global Environment Record 생성
        - Object Environment Record(객체 환경 레코드) 생성
        - Declarative Environment Record(선언적 환경 레코성 생성
      • this 바인딩
      • 외부 렉시컬 환경에 대한 참조 결정
  3. Globla Code 실행
    • 전역 코드의 순차적 실행, 변수 할당 시작
    • 식별자 결정 : 어느 스코프에 있는 식별자를 참조할 것인지 결정
      - 스코프 체인의 동작 원리
      • 실행 중인 Execution context에서 식별자 검색 시작
      • 선언된 식별자는 Execution context의 렉시컬 환경의 환경 레코드에 등록됨
      • 실행 중인 Execution context에서 식별자를 찾을 수 없으면 상위 스코프로 이동해 검색
        (외부 렉시컬 환경에 대한 참조가 가리키는 렉시컬 환경)
  4. Function code 평가 : Global code 실행 일시 중단, 함수 내부로 코드 제어권 이동
    1. Function Execution context 생성
      • 생성된 Function execution context는 function lexical environment가 완성된 다음 execution context stack에 push됨.
      • execution context stack의 최상위에 위치함 (running execution context)
    2. Function Lexical Environment 생성
      • function lexical environment를 생성하고 function execution context에 바인딩함.
      • 렉시컬 환경은 환경 레코드와 외부 렉시컬 환경에 대한 참조로 구성
      1. Function Environment Record 생성
        • 매개변수, arguments 객체, 지역변수, 중첩 함수 등록 및 관리
      2. this 바인딩
        • 함수 환경 레코드 내 this 바인딩
        • 일반 함수로 호출되었을 경우 전역 객체를 가리킴
      3. 외부 렉시컬 환경에 대한 참조 결정
        • 함수의 정의가 평가된 시점에 running execution context의 렉시컬 환경의 참조 할당
        • 일반 함수는 전역 코드 평가 시점에 평가되므로 이 시점의 running execution context는 global execution context임
        • 전역 함수의 경우 외부 렉시컬 환경에 대한 참조는 전역 렉시컬 환경의 참조가 할당됨
  5. Function code 실행
    • runtime 시작, 함수 소스코드 순차적으로 실행
    • 매개변수 인수 할당 및 변수 할당문 실행
    • 식별자 결정을 위해 실행 중인 실행 컨텍스트의 렉시커러 환경에서 식별자 검색
      -> running execution context는 현재 function execution context!
    • running execution context의 렉시컬 환경에서 식별자를 검색할 수 없다면 외부 렉시컬 환경에 대한 참조가 가리키는 렉시컬 환경으로 이동해 식별자 검색
      ex)
      //global scope
      let a = 0;
      let b = 1;
      function test_1(n) {
      // test_1 function scope
      	let a = 1;
          let c = 3;
          
          function test_2(m) {
          // test_2 function scope
          	let d = 3;
              console.log(a + b + c + d + n + m);
          }
          test_2(5);
      }
      
      test_1(7);
      • console.log는 test_2에서 호출되었지만 test_2의 scope에서 찾을 수 없음
      • scope chain에서 검색함 -> running execution context의 렉시컬 환경에서 시작해 외부 렉시컬 환경에 대한 참조로 이어지는 렉시컬 환경의 연속!
      • test_2의 lexical 환경에서는 검색 불가능 -> test_1의 lexical 환경으로 이동 -> global lexical 환경으로 이동 -> console 식별자 확인
      • global : b, test_1 : [a, c, n], test_2 : d, m
  6. Function code 실행 종료
    • 현재 실행 중인 함수가 종료되면 execution context stack에서 function execution context가 pop되어 running execution context가 변경됨
  7. Global code 실행 종료
    • call stack에서 global execution context를 제외한 모든 context가 모두 pop된 후 global code도 모두 실행이 종료되면 global execution context도 execution context stack에서 pop되어 stack이 비워짐

Execution Context와 Block Level Scope

  • var로 선언한 변수는 function level scope를 따름
  • let, const 변수는 block level scope를 따름
  • 따라서 if, for, while, try/catch 등 code block 내에서 선언된 let, const 변수는 해당 code block을 위한 새로운 렉시컬 환경을 생성함
    ex)
    let a = 0;
    
    for (let i = 0; i < 10; ++i) {
    	let b = 1 + i;
    }
    • 여기서 b는 for의 code block에서 선언되었기 때문에 for문의 scope에 존재한다.
    • for문의 code block이 생성한 렉시컬 환경은 반복해서 실행될 때 마다 식별자 값을 유지해야 함
    • 독립적인 렉시컬 환경을 생성해 식별자의 값을 유지할 수 있다 -> 클로저!
profile
욕심 많은 데이터쟁이

0개의 댓글

관련 채용 정보