[HOW]실행 컨텍스트는 어떻게 동작할까?

HOW

 ⋅ Dec 13, 2023 ⋅ 3 min read

how
how

자바스크립트의 실행 컨텍스트는 소스코드를 실행하고 관리하는 중요한 요소입니다. 실행 컨텍스트가 어떻게 생성되며 동작하는지 안다면 자바스크립트의 동작 과정에 대해 파악할 수 있습니다. 지금부터 자바스크립트의 실행 컨텍스트 생성과 동작 과정에 대해 알아보도록 하겠습니다.

1. 전역 객체 생성

전역 객체는 전역 코드가 평가되기 전에 생성됩니다. 전역 객체 또한 Object의 상속으로 생성되며 프로토타입 체인 중 하나입니다.

2. 전역 코드 평가

전역 객체 생성 후 소스코드를 로드하여 전역 코드를 평가합니다. 전역 코드의 평가 순서는 다음과 같습니다.

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

    전역 실행 컨텍스트를 생성하여 실행 컨텍스트 스택에 담습니다. 실행 컨텍스트 스택은 비어있었기 때문에 전역 실행 컨텍스트는 곧바로 실행 중인 실행 컨텍스트가 됩니다.

  2. 전역 렉시컬 환경 생성

    전역 렉시컬 환경을 생성하여 전역 실행 컨텍스트에 바인딩 합니다.

    1. 전역 환경 레코드 생성

      전역 렉시컬 환경을 구성하는 전역 환경 레코드는 전역 변수를 관리하는 전역 스코프와 전역 객체의 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체를 제공합니다. var 키워드로 선언한 전역 변수와 let, const로 선언한 전역 변수의 구분하여 관리하기 위해 전역 스코프 역할을 담당하는 전역 환경 레코드는 객체 환경 레코드선언적 환경 레코드로 구성되어 있습니다. 객체 환경 레코드와 선언적 환경 레코드는 협력을 통해 전역 스코프와 전역 객체를 관리합니다.

      1. 객체 환경 레코드 생성

        객체 환경 레코드는 var 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수, 빌트인 전역 프로퍼티와 빌트인 전역 함수, 표준 빌트인 객체를 관리합니다. 객체 환경 레코드는 전역 객체인 BindingObject와 연결됩니다. 전역 코드 평가 과정에서 var 키워드의 전역 변수와 함수 선언문으로 정의된 전역 함수는 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 됩니다.

        var 키워드로 선언한 변수는 선언과 초기화가 동시에 이루어져 변수 선언문 이전에도 참조할 수 있습니다. 하지만 암묵적으로 undefined를 바인딩하기 때문에 선언문 이전 참조 시 undefined를 반환한다. 이 동작은 변수 호이스팅이 발생하는 원인이기도 합니다.

        함수 선언문으로 정의한 함수 평가 후 BindingObject를 통해 전역 객체에 함수 이름과 동일한 이름의 key로 등록하고 생성된 함수 객체를 할당합니다. 따라서, 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있으며 이는 변수 호이스팅과 함수 호이스팅의 차이점이기도 합니다.

      2. 선언적 환경 레코드 생성

        선언적 환경 레코드는 let, const 키워드로 선언한 전역 변수를 관리합니다. let과 const로 선언된 변수는 전역 객체의 프로퍼티에 등록되지 않고 개념적인 블록에 존재하게 되는데 개념적인 블록이 바로 선언적 환경 레코드입니다.

        const 키워드의 변수의 경우 선언과 초기화가 분리되어 진행되기 때문에 변수 선언문에 도달하기 전까지 일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지게 됩니다. let, const 키워드도 변수 호이스팅이 발생하기는 하지만, 변수 선언문 도달 전까지 일시적 사각지대에 빠지기 때문에 참조할 수 없습니다.

    2. this 바인딩

      전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 전역 객체를 가리키는 this가 바인딩 됩니다.

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

      외부 렉시컬 환경에 대한 참조는 현재 평가 중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경인 상위 스코프를 가리킵니다. 상위 스코프를 가리킴으로써 단방향 링크드 리스트인 스코프 체인을 구현합니다.

      전역 코드를 포함하는 소스코드가 존재하지 않기 때문에 현재의 상황에서는 null이 할당되게 됩니다. 이는 전역 렉시컬 환경이 스코프 체인의 종점임을 뜻합니다.

3. 전역 코드 실행

전역 코드가 실행되며 전역 변수의 값이 할당되고 함수가 호출됩니다. 변수 할당문이나 함수 호출문을 실행하기 위해서는 이들이 선언된 식별자인지 확인해야 합니다. 동일한 이름의 식별자가 여러 스코프에 존재할 수 있기 때문에 어느 스코프의 식별자를 참조해야 하는지 결정하는 것을 식별자 결정이라고 합니다.

식별자 결정을 위해서 실행 중인 실행 컨텍스트에서 식별자를 검색하여 해당 실행 컨텍스트의 렉시컬 환경에 존재하지 않는 경우 외부 렉시컬 환경이 가리키는 상위 스코프로 이동하여 검색합니다. 이는 스코프 체인의 동작 원리입니다.

4. 함수 코드 평가

함수가 호출되면 전역 코드의 실행을 멈추고 함수 내부로 코드의 제어권이 이동됩니다. 이후 함수 코드를 평가하며 함수 코드의 평가 순서는 다음과 같습니다.

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

    함수의 실행 컨텍스트를 생성하여 함수 렉시컬 환경이 완성되면 실행 컨텍스트 스택에 담습니다. 함수 실행 컨텍스트는 실행 컨텍스트 스택의 최상단에 위치하게 되며 실행 중인 실행 컨텍스트가 됩니다.

  2. 함수 렉시컬 환경 생성

    함수 렉시컬 환경을 생하여 함수 실행 컨텍스트에 바인딩 됩니다.

    1. 함수 환경 레코드 생성

      함수 환경 레코드는 함수 렉시컬 환경 구성 요소 중 하나로 매개 변수, argument 객체, 함수 내부에서 선언한 지역 변수와 중첩 함수를 등록하고 관리합니다.

    2. this 바인딩

      함수 환경 레코드의 [[ThisValue]] 내부 슬롯에 this가 바인딩 되며 바인딩 될 객체는 함수 호출 방식에 따라 결정됩니다.

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

      외부 렉시컬 환경에 대한 참조에는 함수 정의가 평가된 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 할당됩니다.

      자바스크립트는 함수 호출 위치가 아닌 정의 위치에 따라 상위 스코프를 결정합니다. 자바스크립트 엔진은 함수 정의를 평가하려 함수 객체 생성 시 실행 중인 실행 컨텍스트의 렉시컬 환경(함수의 상위 스코프)을 함수 객체 내부 슬롯인 [[Environment]]에 저장합니다. 함수 렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 할당하는 것은 [[Environment]]에 저장된 렉시컬 환경의 참조로 이는 렉시컬 스코프를 구현하는 메커니즘이며 클로저를 이해할 수 있는 단서이기도 합니다.

5. 함수 코드 실행

함수 소스코드의 순차 실행으로 매개 변수에 인수가 할당되고 변수 할당문이 실행되어 지역 변수에 값이 할당됩니다.

6. 함수 코드 실행 종료

더 이상 실행할 함수의 소스코드가 없는 경우 실행 컨텍스트 스택에서 함수 실행 컨텍스트를 제거합니다. 함수 실행 컨텍스트의 제거가 함수 렉시컬 환경의 제거를 의미하는 것은 아닙니다. 렉시컬 환경은 실행 컨텍스트에 참조되지만 독립적인 객체로 다른 곳에서 참조되고 있다면 사라지지 않습니다.


참고

이웅모, ⌈모던 자바스크립트 - Deep Dive⌋, 2020, 23_실행 컨텍스트(p.368 - 386)

LINKS

© Copyright 2021

made by React.js & gatsby