[ TIL 59 ] JavaScript Deep Dive 23. 실행 컨텍스트

angie·2022년 12월 6일
0

JavaScript Deep Dive

목록 보기
11/18
post-thumbnail

1. 실행컨텍스트

  • 자바스크립트의 동작 원리를 담고 있는 핵심 개념
  • 코드가 실행되기 위해 필요한 환경

1) 소스코드의 타입

  • 소스코드의 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리 내용이 다름
소스코드의 타입설명
전역코드전역에 존재하는 소스코드
함수코드함수 내부에 존재하는 소스코드
eval 코드빌트인 전역 함수인 eval 함수에 인수로 전달되어 실행되는 소스코드
모듈 코드모듈 내부에 존재하는 소스코드
  1. 전역 코드 → 전역 실행 컨텍스트
    • 전역 스코프를 생성
    • var 키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수를 전역 객체의 프로퍼티와 메서드로 바인딩
    • 전역 객체와 연결되어야함
  2. 함수 코드 → 함수 실행 컨텍스트
    • 지역 스코프 생성
    • 지역 변수, 매개변수, arguments 객체를 관리
  3. eval 코드 → eval 함수 실행 컨텍스트
    • strick mode에서 자신만의 독자적인 스코프 생성
  4. 모듈 코드
    • 모듈별로 독립적인 모듈 스코프 생성

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

  1. 소스코드의 평가 과정
  • 실행 컨텍스트를 생성
  • 변수, 함수 등의 선언문을 먼저 실행하여 변수나 함수 식별자를 스코프에 등록
  1. 소스코드의 실행 과정
  • 런타임이 시작
  • 소스코드 실행에 필요한 정보(변수, 함수 등)를 스코프에서 검색해 사용
  • 소스코드의 실행 결과는 다시 스코프에 등록

소스코드가 평가되고 실행되는 과정 예시

// 전역 변수 선언
const x = 1;
const y = 2;

// 함수 정의
function foo(a) {
  // 지역 변수 선언
  const x = 10;
  const y = 20;

  // 메서드 호출
  console.log(a + x + y); // 130
}

// 함수 호출
foo(100);

// 메서드 호출
console.log(x + y); // 3
  1. 전역 코드 평가

    • 선언문(변수 선언문, 함수 선언문) 먼저 실행하여 생성된 전역 변수와 전역 함수가 전역 스코프에 등록
  2. 전역 코드 실행

    • 런타임 시작
    • 전역 변수에 값의 할당
    • 함수의 호출 → 함수 호출 시 전역 코드 실행을 일시 중단하고 함수 내부로 진입
  3. 함수 코드 평가

    • 매개변수와 지역 변수 선언문을 먼저 실행하여 생성된 매개변수와 지역변수가 지역 스코프에 등록
    • arguments 객체가 생성되어 지역 스코프에 등록
    • this 바인딩을 결정 (함수가 호출되는 방식에 따라 결정)
  4. 함수 코드 실행

    • 런타임 시작

    • 매개 변수와 지역 변수에 값이 할당

    • foo

      함수 내부의

      console.log

      메서드 호출

      • console 식별자를 검색
      • log 프로퍼티를 console 객체에서 검색
      • 전달된 표현식 a + x + y가 평가됨 (각 변수를 검색)
    • 함수 코드 실행이 종료되며 전역 코드로 돌아감

3) 실행 컨텍스트 스택

  • 전역 코드는 평가될 때, 함수 코드는 호출될 때 실행 컨텍스트가 생성되고 생성된 실행 컨텍스트는 스택 자료 구조로 관리됨
  • 코드의 실행 순서를 관리하는 LIFO(후입 선출)의 구조를 가지는 자료구조

예시

const x = 1;

function foo () {
  const y = 2;

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

foo(); // 6

2. 실행 컨텍스트 구조

1) 렉시컬 환경 (Lexical Environment)

  • 스코프와 식별자를 관리
  • 식별자와 특정 변수의 매핑을 지속적으로 트래킹하는 엔진의 내부 구조
  • 식별자와 변수의 맵핑이 이루어지는 공간

⇒ 함수 코드가 평가될 때 생성된다

⇒ 렉시컬 환경을 스코프라고 부르는 경우가 많다.

렉시컬 환경의 구성

2개의 컴포넌트로 이루어져 있다.

  1. 환경 레코드 (Environment Record)
    • 현재 실행 컨텍스트 내부의 변수 또는 함수의 선언이 저장되는 공간
    • 스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩된 값을 관리하는 저장소
  2. 외부 렉시컬 환경에 대한 참조 (Outer Lexical Environment Reference) : 상위 스코프의 렉시컬 환경

(1) 환경 레코드

두 가지 타입이 있다

  1. 객체 환경 레코드 (Object Environment Record)
  2. 선언적 환경 레코드 (Declarative Environment Record)

(2) 외부 렉시컬 환경에 대한 참조

  • 스코프 체인에 상응하는 개념
  • 하위스코프에서 상위스코프의 방향으로만 연결되어 있는 단방향 연결 리스트로 구현되어 있다.

2) 변수 환경 (Variable Environment)

  • 렉시컬 환경과 동일
  • 차이점
    • 렉시컬 환경 : 함수 선언 및 변수(let, const) 바인딩 저장
    • 변수 환경 : 변수(var) 바인딩만 저장

3. 실행 컨텍스트 생성 과정

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

위 예시 코드에서 실행 컨텍스트가 생성되는 과정은 아래와 같다.

  1. 전역 객체 생성
  2. 전역 코드 평가
    • 전역 실행 컨텍스트 생성
    • 전역 렉시컬 환경 생성
      • 전역 환경 레코드 생성
        • 객체 환경 레코드 생성
        • 선언적 환경 레코드 생성
      • this 바인딩
      • 외부 렉시컬 환경에 대한 참조 결정
  3. 전역 코드 실행
  4. foo 함수 코드 평가
    • 함수 실행 컨텍스트 생성
    • 함수 렉시컬 환경 생성
      • 함수 환경 레코드 생성
      • this 바인딩
      • 외부 렉시컬 환경에 대한 참조 결정
  5. foo 함수 코드 실행
  6. bar 함수 코드 평가
  7. bar 함수 코드 실행

1) 전역 객체 생성

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

2) 전역 코드 평가

최종적으로 생성된 전역 실행 컨텍스트와 렉시컬 환경의 구조

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

  • 비어있는 전역 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시

(2) 전역 렉시컬 환경 생성

  • 전역 렉시컬 환경을 생성하고 전역 실행 컨텍스트에 바인딩
  1. 전역 환경 레코드 생성

    • 전역 변수를 관리하는 전역 스코프, 전역 객체의 빌트인 전역 프로퍼티와 빌트인 전역 함수, 표준 빌트인 객체를 제공
    1. 객체 환경 레코드 생성
      • var 키워드로 선언한 전역 변수와 전역함수, 전역 프로퍼티, 표준 빌트인 객체를 관리
      • var 키워드로 선언한 전역 변수와 함수 선언문으로 정의된 전역 함수는 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 된다.
    2. 선언적 환경 레코드 생성
      • let, const 키워드로 선언한 전역 변수를 관리
  2. this 바인딩

  3. 외부 렉시컬 환경에 대한 참조 결정

    • 현재 평가중인 코드는 전역 코드이므로 상위 스코프의 코드는 없다. 따라서 null이 할당된다.

3) 전역 코드 실행

  • 순차적으로 코드가 실행되어 변수에 값이 할당된다.
  • 식별자를 검색할 때는 현재 실행 컨텍스트에서 식별자를 검색하기 시작하여 외부 렉시컬 환경에 대한 참조가 가리키는 상위 스코프로 이동하여 식별자를 검색한다.

4) foo 함수 코드 평가

  • 함수가 호출되면 전역 코드의 실행을 일시 중단하고 함수 내부로 코드 제어권이 이동

최종적으로 생성된 foo 함수 실행 컨텍스트와 렉시컬 환경의 구조

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

  • 생성된 함수 실행 컨텍스트는 함수 렉시컬 환경이 완성된 다음 실행 컨텍스트 스택에 푸시

(2) 함수 렉시컬 환경 생성

  • foo 함수 렉시컬 환경을 생성하고 foo 함수 실행 컨텍스트에 바인딩
  1. 함수 환경 레코드 생성
    • 매개변수, arguments 객체, 함수 내부에서 선언한 지역 변수와 중첩 함수를 등록하고 관리
  2. this 바인딩
    • 함수 호출 방식에 따라 결정
    • foo 함수 내부에서 this를 참조하면 함수 환경 레코드의 [[ThisValue]] 내부 슬롯에 바인딩되어 있는 객체가 반환됨
  3. 외부 렉시컬 환경에 대한 참조 결정
    • foo 함수 정의가 평가된 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 할당

5) foo 함수 코드 실행

  • 런타임이 시작되고 foo 함수의 코드가 순차적으로 실행
  • 식별자 결정은 현재 실행 중인 컨텍스트의 렉시컬 환경에서 식별자를 검색하기 시작

6) bar 함수 코드 평가 & 실행

  • 위와 동일

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

  • 함수 레벨 스코프 : 함수 코드 블록만 지역 스코프로 인정
  • 블록 레벨 스코프 : 모든 코드 블록(함수, if문, for 문, while 문, try/catch문 등)을 지역 스코프로 인정
  • var 키워드는 함수 레벨 스코프를 따르며, let/const 키워드는 블록 레벨 스코프를 따른다.

블록 레벨 스코프와 렉시컬 환경

let x = 1;

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

console.log(x); // 1
  • if 문이 실행될 때, let 키워드로 변수 x가 선언되었으므로 블록 레벨 스코프를 생성
  • 실행 컨텍스트가 새롭게 생성되는 것이 아니라, 현재 실행 컨텍스트에서 렉시컬 환경을 새롭게 생성하여 기존의 것과 교체한다.
  • 반복문에서는 코드 블록이 반복해서 실행될 때마다 코드 블록을 위한 새로운 렉시컬 환경을 생성
profile
better than more

0개의 댓글