본문 바로가기

JavaScript

[Deep dive] 23장 실행 컨텍스트

23.1 소스코드의 타입 

 

- 소스코드의 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리내용이 다름

 

1) 전역 코드 

 

- 전역 실행 컨텍스트 생성

- 전역 변수를 관리하기 위해 최상위 스코프인 전역 스코프를 생성

- var 키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수를 전역 객체의 프로퍼티와 메서드로 바인딩하고 참조하기 위해 전역 객체와 연결

 

2) 함수 코드 

 

- 함수 실행 컨텍스트 생성

- 지역 스코프를 생성하고 지역 변수, 매개 변수 , arguments 객체를 관리 

- 생성한 지역 스코프를 전역 스코프에서 시작하는 스코프 체인의 일원으로 연결

 

3) eval 코드 

 

- eval 실행 컨텍스트 생성

- strct mode(엄격 모드)에서 자신만의 독자적인 스코프 생성

 

4) 모듈 코드 

 

- 모듈 실행 컨텍스트 생성

 - 모듈별로 독립적인 모듈 스코프 생성

 

 

23.2 소스코드의 평가와 실행 

 

- 자바스크립트 엔진은 소스 코드를 1) 소스코드의 평가 2) 소스코드의 실행 과정으로 나누어 처리 

 

ex)

var x;
x = 1;

1) 소스코드의 평가 

 

- 변수 선언문 var x;를 먼저 실행 

- 생성된 변수 식별자 x는 실행 컨텍스트가 관리하는 스코프에 등록되고 undefined로 초기화 

 

2) 소스코드의 실행

 

- 변수 할당문 x=1;만 실행 

- x 변수에 값을 할당하려면 먼저 x 변수가 선언된 변수인지 확인

- 실행 컨텍스트가 관리하는 스코프에 x 변수가 등록되어 있는지 확인 

- 스코프에 등록되어 있다면 x 변수는 소스코드 평가 과정에서 선언문이 실행되어 등록된 변수 

 

 

23.3 실행 컨텍스트의 역할 

 

실행 컨텍스트 (execution context)

 

- 자바스크립트의 동작 원리를 담고 있는 핵심 개념

- 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역

- 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 메커니즘

- 모든 코드는 실행 컨텍스트를 통해 실행되고 관리 

 

- 식별자와 스코프는 실행 컨텍스트의 렉시컬 환경으로 관리 

- 코드 실행 순서는 실행 컨텍스트 스택으로 관리 

 

 

23.4 실행 컨텍스트 스택

 

- 자바스크립트 엔진은 먼저 전역 코드를 평가하여 전역 실행 컨텍스트 생성

- 함수가 호출되면 함수 코드를 평가하여 함수 실행 컨텍스트 생성

const x = 1;

function foo() {
  const y = 2;

  function bar() {
    const z = 3;
    console.log(x+y+z);
  }
  bar();
}

foo(); //6

- 코드가 실행되는 시간의  흐름에 따라 실행 컨텍스트 스택에는 실행 컨텍스트가 추가(push)되고 제거(pop)됨

- 실행 컨텍스트 스택의 최상위에 존재하는 실행컨텍스트는 실행  중인 코드의 실행 컨텍스트 

 

1) 전역 코드의 평가와 실행 

 

 - 전역 코드를 평가하여 전역 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시 

 - 전역 변수 x와 전역 변수 foo는 전역 실행 컨텍스트에 등록 

 - 전역 코드가 실행되면 전역 변수 x에 값이 할당되고 전역 함수 foo가 호출

 

2) foo 함수 코드의 평가와 실행 

 

 - 전역 함수 foo가 호출되면 코드의 제어권이 foo 함수 내부로 이동

 - foo 함수 내부의 함수 코드를 평가하여 foo 함수 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시

 - foo 함수의 지역 변수 y와 중첩 함수 bar가 foo 함수 실행 컨텍스트에 등록 

 

3) bar 함수 코드의 평가와 실행 

 

 - 중첩 함수 bar가 호출되면 코드의 제어권인 bar 함수 내부로 이동 

 - bar 함수 내부의 함수 코드를 평가하여 bar 함수 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시 

 - bar 함수 의 지역 변수 z가 bar 함수 실행 컨텍스트에 등록

 - bar 함수 코드가 실행되면 지역 변수 z에 값이 할당되고 console.log 메서드를 호출한 이후 bar함수는 종료 

 

4) foo 함수 코드로 복귀 

 

- bar 함수가 종료되면 코드의 제어권은 다시 foo 함수로 이동 

- bar 함수 실행 컨텍스트를 실행 컨텍스트 스택에서 팝하여 제거 

- foo 함수 종료 

 

5) 전역 코드로 복귀 

 

-  foo 함수가 종료되면 코드의 제어권은 다시 전역 코드로 이동 

-  foo  함수 실행 컨텍스트를 실행 컨텍스트 스택에서 팝하여 제거 

- 전역 실행 컨텍스트도 실행 컨텍스트 스택에서 팝하여 제거 

 

 

23.5 렉시컬 환경 

 

- 식별자식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트 

- 키와 값을 갖는 객체 형태의 스코프 (전역, 함수, 블록 스코프)를 생성하여 식별자를 키로 등록하고 식별자에 바인딩된 값을 관리 

- 스코프를 구분하여 식별자를 등록하고 관리하는 저장소 역할을 하는 렉시컬 스코프의 실체 

- LexicalEnvironment 컴포넌트와 VariableEnvironment 컴포넌트로 구성 

 

1) 환경 레코드 (Environment Record)

 

 - 스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩된 값을 관리하는 저장소 

 

2) 외부 렉시컬 환경에 대한 참조 (Outer Lexical Environment Reference)

 

 - 외부 렉시컬 환경에 대한 참조는 상위 스코프를 가리킴

 - 상위 스코프 

  -> 해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경 

 - 외부 렉시컬 환경에 대한 참조를 통해 단방향 링크드 리스트인 스코프 체인을 구현

 

 

23.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); //42

 

23.6.1 전역 객체 생성 

 

- 전역 객체는 전역 코드가 평가되기 이전에 생성

- 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체 추가

- 동작환경에 따라 클라이언트 사이드 Web API 또는 특정 환경을 위한 호스트 객체 포함 

 

 

23.6.2 전역 코드 평가 

 

1) 전역 실행 컨텍스트 생성

 

- 전역 실행 컨텍스트를 생성하여 실행 컨텍스트 스택에 푸시

 

2) 전역 렉시컬 환경 생성

 

 - 전역 렉시컬 환경(Global Lexical Environment)을 생성하고 전역 실행 컨텍스트에 바인딩

 

 2.1) 전역 환경 레코드 생성 

 

 - 전역 변수를 관리하는 전역 스콮, 전역 객체의 빌트인 전역 프로퍼티와 빌트인 전역 함수, 표준 빌트인 객체 제공

 - 객체 환경 레코드와 선언적 환경 레코드로 구성 

 

 ● 객체 환경 레코드(Object Envrionment Record)생성

 

 - var 키워드로 선언한 전역 변수,

 - 함수 선언 문으로 정의한 전역 함수,

 - 빌트인 전역 프로퍼티와 빌트인 전역함수, 표준 빌트인 객체 관리 

 

 - BindingObject는 "전역 객체 생성"에서 생성된 전역 객체 

 - 전역 코드 평가 과정에서 var 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수는 전역 환경 레코드의 객체 환경 레코드에 연결된 BindingObject를 통해 객체의 프로퍼티와 메서드가 됨

 

 - x 변수는 var 키워드로 선언한 변수 

 - "선언 단계"와 "초기화 단계"가 동시에 진행 

 - 전역 코드 평가 시점에 객체 환경 레코드에 바인딩된 BindingObject를 통해 전역 객체에 변수 식별자를 키로 등록한 다음, 암묵적으로 undefined를 바인딩 (변수 호이스팅)

 

  선언적 환경 레코드(Declarative Environment Record) 생성

 

  - let, const 키워드로 선언한 전역 변수는 선언적 환경 레코드에 등록되고 관리 

  - const 키워드로 선언한 변수는 "선언 단계"와 "초기화 단계"가 분리되어 진행 

   ( 런타임에 실행 흐름이 변수 선언문에 도달하기 전까지 일시적 사각지대(TDZ)에 빠지게 됨

 

2.2) this 바인딩

 

 - 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 this 바인딩

 - 전역 코드에서 this는 전역 객체를 가리키므로 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에는 전역 객체가 바인딩

 - 전역 코드에서 this를 참조하면 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 바인딩되어 있는 객체 반환

 

2.3) 외부 렉시컬 환경에 대한 참조 결정

 

 - 전역 렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 null이 할당

 - 전역 렉시컬 환경이 스코프 체인의 종점에 존재함을 의미 

 

 

23.6.3 전역 코드 실행 

 

- 변수 할당문이 실행되어 전역 변수 x,y에 값이 할당 

- foo 함수가 호출 

- 식별자 결정 실행 

 

23.6.4 foo 함수 코드 평가 

 

1) 함수 실행 컨텍스트 생성

 

 - foo 함수 실행 컨텍스트 생성

 

2) 함수 렉시컬 환경 생성 

 

 - foo 함수 렉시컬 환경을 생성하고 foo 함수 실행 컨텍스트에 바인딩

 

 2.1) 함수 환경 레코드 생성

 

 - 매개변수, arguments 객체, 함수 내부에서 선언한 지역 변수와 중첩함수를 등록하고 관리 

 

 2.2) this 바인딩

 

 - 함수 환경 레코드의  [[ThisValue]] 내부 슬롯에 this가 바인딩 

- [[ThisValue]] 내부 슬롯에 바인딩될 객체는 함수 호출 방식에 따라 결정 

 

2.3) 외부 렉시컬 환경에 대한 참조 결정 

 

 - foo 함수 정의가 평가된 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 할당

 - 자바스크립트 엔진은 함수 정의를 평가하여 함수 객체를 생성할 때 함수의 상위 스코프함수 객체의 내부 슬롯 [[Environment]]에 저장 

 

 

23.6.5 foo 함수 코드 실행 

 

- 매개변수에 인수가 할당되고, 변수 할당문이 실행되어 지역 변수 x,y에 값이 할당 

- 함수 bar 호출

- 식별자 결정 실행 

 

 

23.6.6 bar 함수 코드 평가 

 

- bar 함수가 호출되면 bar 함수 내부로 코드의 제어권 이동

 

 

23.6.7 bar 함수 코드 실행 

 

 - 매개변수에 인수가 할당되고, 변수 할당문이 실행되어 지역 변수 z에 값이 할당 

 - cosole.log(a+b+x+y+z); 실행 

 

 1) console 식별자 검색 

 

  - console 식별자를 스코프 체인에서 검색 

  - 식별자를 검색할 때는 언제나 현재 실행중인 실행 컨텍스트의 렉시컬 환경에서 검색하기 시작

  - 전역 렉시컬 환경으로 이동하여 console 식별자를 검색 

  - console 식별자는 객체 환경 레코드의 BindingObejct를 통해 전역 객체에서 찾을 수 있음

 

 2) log 메서드 검색 

 

 - console 객체에서 log 메서드를 검색 

 - console 객체의 프로토타입 체인을 통해 메서드를 검색 

 - log 메서드는 상속된 프로퍼티가 아니라 console 객체가 직접 소유하는 프로퍼티 

console.hasOwnProperty('log'); //true

 

3) 표현식 a+b+x+y+z의 평가 

 

 - a,b,x,y,z 식별자를 검색 

 - a 식별자는 foo 함수 렉시컬 환경에서, b 식별자는 bar 함수 렉시컬 환경에서, x와 y 식별자는 foo 함수 렉시컬 환경에서 

 z 식별자는 bar 함수 렉시컬 환경에서 검색

 

4) console.log 메서드 호출 

 

- 표현식  a+b+x+y+z가 평가되어 생성한 값 42를 console.log 메서드에 전달되어 호출

 

 

23.6.8 bar 함수 코드 실행 종료 

 

- bar 함수 실행 컨텍스트가 소멸되었다 하더라도 만약 bar 함수 렉시컬 환경을 누군가 참조하고 있다면 

 bar 함수 렉시컬 환경은 소멸하지 않음

 

- foo 함수 코드 실행 종료 

- 전역 코드 실행 종료 

 

 

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

 

- let, const 키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정하는 블록 레벨 스코프 (block-level scope)를 따름

let x = 1;

if(true) {
  let x = 10;
  console.log(x); //10
}

console.log(x); //1

- for문의 변수 선언문에 let 키워드를 사용한 for문은 코드 블록이 반복해서 실행될 때마다 코드 블록을 위한 새로운 렉시컬 환경을 생성

- 함수의 상위 스코프는 for 문의 코드 블록이 반복해서 실행될 때 마다 식별자의 값을 유지해야함 

- for 문의 코드 블록이 반복해서 실행될 때마다 독립적인 렉시컬 환경을 생성하여 식별자의 값을 유지 

'JavaScript' 카테고리의 다른 글

[Deep dive] 25장 클래스 (1)  (0) 2023.08.15
[Deep dive] 24장 클로저  (0) 2023.08.14
[Deep dive] 22장 this  (0) 2023.08.11
[Deep dive] 21장 빌트인 객체  (0) 2023.08.11
[Deep dive] 20장 strict mode  (0) 2023.08.11