23. 실행 컨텍스트




1. 소스코드의 타입

  • 소스코드 구분 이유 : 소스코드 타입에 따라 실행 컨텍스트를 생성하는 과정, 관리 내용이 달라서
  • 전역코드
    • 함수, 클래스 내부 코드는 x
    • 전역 변수를 관리하기 위해 최상위 스코프인 전역 스코프를 생성해야 한다.
    • var 키워드로 선언된 전역 변수와 함수선언문으로 정의된 전역 함수를 전역객체의 프로퍼티와 메서드로 바인딩하고 참조하기 위해, 전역객체와 연결해야 한다.
    • 이를 위해 전역 코드가 평가되면 전역 실행 컨텍스트가 생성된다.
  • 함수코드
    • 중첩된 함수, 클래스 내부 코드는 x
    • 지역 스코프를 생성
    • 지역 변수, 매개변수, arguments 객체를 관리
    • 생성한 지역 스코프를 전역 스코프에서 시작하는 스코프 체인의 일원으로 연결
    • 함수 코드가 평가되면 함수 실행 컨텍스트가 생성
  • eval 코드
    • strict mode에서 자신만의 독자적인 스코프를 실행
    • eval 코드가 평가되면 eval 실행 컨텍스트가 생성
  • 모듈 코드
    • 모듈별로 독립적인 모듈 스코프 생성

2. 소스코드의 평가와 실행

  • 소스 코드 평가 과정
    • 실행 콘텍스트 생성
    • 변수, 함수 등의 선언문만 먼저 실행 > 생성된 변수, 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록
  • 소스 코드 실행 과정
    • 선언문을 제외한 소스코드가 순차적으로 실행
    • 런타임 시작
    • 소스코드 실행에 필요한 정보(변수, 함수의 참조)를 실행 컨텍스트가 관리하는 스코프에서 검색해 취득
    • 변수 값의 변경 등 소스코드의 실행 결과는 실행 컨텍스트가 관리하는 스코프에 등록

3. 실행 컨텍스트의 역할

  • 코드가 실행되려면 스코프, 식별자, 코드 실행 순서 등의 관리가 필요하다
    • 선언에 의해 생성된 모든 식별자를 스코프로 구분하여 등록하고, 상태변화를 지속적으로 관리한다.
    • 스코프는 중첩 관계에 의해 스코프 체인을 형성한다. > 스코프 체인을 통해 상위 스코프로 이동하며 식별자를 검색할 수 있어야 한다.
    • 현재 실행중인 코드의 실행 순서를 변경할 수 있어야 하며, 다시 되돌아갈 수 있어야 한다.
  • 실행 컨텍스트는 소스코들르 실행하는데 필요한 환경을 제공하고, 코드의 실행 결과를 실제로 관리하는 영역
  • 식별자를 등록하고 관리하는 스코프 + 코드 실행 순서 관리를 구현한 내부 메커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.
  • 렉시컬 환경 : 식별자와 스코프
  • 실행 컨텍스트 스택 : 코드 실행 순서

4. 실행 컨텍스트 스택

  • 실행 컨텍스트 스택은 코드의 실행 순서를 관리
  • 소스코드가 평가되면 실행 컨텍스트 생성 > 스택에 push
  • 실행 컨텍스트 스택 최상위에 존재하는 실행 컨텍스트는 언제나 현지 실행 중인 코드의 실행 컨텍스트
    • 실행 컨텐스트 스택의 최상위 실행 컨텍스트 : 실행중인 실행 컨텍스트

5. 렉시컬 환경

  • 식별자와, 식별자에 바인딩 된 값, 상위 스코프에 대한 참조를 기록하는 자료구조
  • 실행 컨텍스트를 구성하는 컴포넌트
  • 스코프와 식별자를 관리
  • 키-값을 갖는 객체 형태의 스코프 생성 > 식별자를 키로 등록하고 식별자에 바인딩된 값을 관리
  • 렉시컬 환경 : 스코프를 구분하여 식별자를 등록하고 관리하는 저장소 역할을 하는 렉시컬 스코프의 실체
  • 실행 컨텍스트 = LexicalEnvironment 컴포넌트 + VariableEnvironment 컴포넌트
    • 이 둘은 초기에 Lexial Envirmonment 가리킴
  • 렉시컬 환경 = EnvironmentRecord(환경 레코드) + OuterLexicalEnvironmentReference(외부 렉시컬 환경에 대한 참조)
    • 환경 레코드 : 스코프에 포함된 식별자를 등록하고, 등록된 식별자에 바인딩된 값을 관리하는 저장소
    • 외부 렉시컬 환경에 대한 참조 : 상위 스코프를 가리킨다. (상위 코드의 렉시컬 환경) > 링크드 리스트 스코프 체인 구현

6. 실행 컨텍스트의 생성과 식별자 검색 과정

var x = 1;
const y = 2;

function foo(a) {
  var x = 3;
  const y = 4;

  function bar(b) {
    const z = 5;
    console.log(a + b + x + y + z);
  }
  bar(10);
}

foo(20);

전역 객체 생성

  • 전역 객체는 전역 코드가 평가되기 이전에 생성
  • 전역 객체도 Object.prototype 상속받는다. > 전역객체도 프로토타입 체인의 일원이다.

전역 코드 평가

  • 전역 실행 컨텍스트 생성
    • 실행 컨텍스트 스택에 push
  • 전역 렉시컬 환경 생성
    • 전역 실행 컨텍스트에 바인딩
    • 전역 환경 레코드 생성
      • 전역 환경 레코드 : 전역 변수를 관리하는 전역 스코프, 전역 객체의 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체 제공
      • 전역 환경 레코드 = 객체 환경 레코드, 선언적 환경 레코드로 분류 (전역변수 var, let+const 구분 위해)
      • 객체 환경 레코드 : var 키워드로 선언한 전역 변수, 함수 선언문, 빌트인 전역 프로퍼티, 빌트인 전역함수, 표준 빌트인 객체 관리
      • 선언적 환경 레코드 : let, const 키워드로 선언한 전역 변수 관리
      • 전역 환경 레코드의 객체 환경 레코드와 선언적 환경 레코드는 서로 협력하여, 전역 스코프와 전역 객체(전역 변수의 전역 객체 프로퍼티화)를 관리
      • 객체 환경 레코드 생성
        • BindingObject 객체(전역 객체)와 연결된다.
        • 전역 코드 평가 과정에서, var 키워드로 선언한 전역 변수와 함수 선언문으로 선언한 전역 함수는 전역 환경 레코드의 객채 환경 레코드에 연결된 BindingObejct를 통해 전역 객체의 프로퍼티와 메서드가 된다.
      • 선언적 환경 레코드 생성
        • let, const 키워드로 선언한 전역변수는 선언적 환경 레코드에 등록, 관리
        • 선언단계와 초기화 단계가 분리되어 진행된다. > 일시적 사각 지대에 빠진다 (uninitialized)
    • this 바인딩
      • 전역 환경 레코드의 [[GlobalThisVallue]] 의 내부 슬롯에 this가 바인딩된다.
      • 일반적으로 전역 객체가 바인딩
      • 전역 환경 레코드를 구성하는 객체,선언적 환경 레코드에는 this 바인딩 없다.
        • this 바인딩은 전역 환경 레코드와 함수 환경 레코드에만 존재
    • 외부 렉시컬 환경에 대한 참조 결정
      • 현재 평가중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경(상위 스코프)를 가리킨다.
      • 이를 통해 단방향 링크드 리스크인 스코프 체인 구현

전역 코드 실행

  • 어느 스코프의 식별자를 참조하면 되는지 결정하는 것 : 식별자 결정
    • 식별자 결정을 위해 식별자를 검색할 때는, 실행 중인 실행 컨텍스트에서 식별자를 검색하기 시작

foo 함수 코드 평가

  • 함수 실행 컨텍스트 생성
    • foo 함수 실행 컨텍스트 생성. 생성된 함수 실행 컨텍스트는 함수 렉시컬 환경이 완성된 다음 실행 컨텍스트 스택에 push
  • 함수 렉시컬 환경 생성
    • foo 함수 렉시컬 환경을 생성하고 foo 함수 실행 컨텍스트에 바인딩
    • 함수 환경 레코드 생성
      • 매개변수, arguments 객체, 함수 내부에서 선언한 지역 변수와 중첩 함수를 등록, 관리
    • this 바인딩
      • 함수 환경 레코드의 [[ThisValue]] 내부 슬롯에 this가 바인딩된다. > 호출 방식에 따라 결정
      • foo 는 일반 함수로 호출 > 전역 객체
      • foo 함수 내부에서 this 를 참조하면 함수 환경 레코드의 [[ThisValue]] 내부 슬롯에 바인딩되어있는 객체 반환
    • 외부 렉시컬 환경에 대한 참조 결정
      • foo 함수 정의가 평가된 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 할당
      • foo 는 전역 코드에서 정의된 전역 함수 > 전역 렉시컬 환경의 참조가 할당
    • js는 함수 정의를 평가하여 함수 객체 생성할 때, 현재 실행 중인 실행 컨텍스트의 렉시컬 환경, 즉 함수의 상위 스코프를 함수 객체의 내부 슬롯 [[Environment]]에 저장
      • 힘수 렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 할당되는 것 : 함수의 상위 스코프를 가리키는 함수 객체의 내부 슬롯 [[Environment]] > 렉시컬 스코프를 구현하는 메커니즘

foo 함수 코드 실행

bar 함수 코드 평가

bar 함수 코드 실행

  • console 식별자 검색
  • log 메서드 검색
  • 표현식 a + b + x + y + z 평가
  • console.log 메서드 호출

bar 함수 코드 실행 종료

  • 실행 컨텍스트 스택에서 bar 함수 실행 컨텍스트 pop
    • bar 함수 렉시컬 환경까지 즉시 소멸하는 건 아님
    • 렉시컬 환경은 실행 컨텍스트에게 참조되기는 하지만 독립적 객체
    • bar 함수 실행 컨텍스트가 소멸되었더라도, 만약 bar 함수 렉시컬 환경을 누군가 참조한다면 bar 함수 렉시컬 환경은 소멸 x

foo 함수 코드 실행 종료

전역 코드 실행 종료

7. 실행 컨텍스트와 블록 레벨 스코프

  • var : 함수 레벨 스포크
  • let, const : 블록 레벨 스코프