Excution Context(실행 컨텍스트)

NSH·2022년 5월 14일
0

실행 컨텍스트란?

실행 컨텍스트는 scope, hoisting, this, function, closure 등의 동작원리를 담고 있는 자바스크립트의 핵심 원리이다. 실행 컨텍스트를 이해하고 자바스크립트 코드가 어떻게 동작하는지 알아보자.

실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경이며 실행 가능한 코드는 아래와 같다.

  • 실행 가능한 코드
    • 전역 코드 : 전역 영역에 존재하는 코드
    • 함수 코드 : 함수 내에 존재하는 코드
    • Eval 코드 : eval 함수로 실행되는 코드

자바스크립트 엔진이 코드를 실행하기 위해서는 많은 정보를 알고 있어야 한다. 자바스크립트 엔진은 아래의 정보들을 형상화하고 구분하기 위해서 실행 컨텍스트를 물리적 객체의 형태로 관리한다.

  • 변수 : 전역 변수, 지역 변수, 매개 변수, 객체의 프로퍼티
  • 변수 유효 범위(scope)
  • 함수 선언
  • this
  • 변수

실행 컨텍스트 구조

실행 컨텍스트는 객체의 형태를 가지고 있으며 3개의 프로퍼티가 존재한다.

Variable Object(VO)

Variable Object는 아래의 정보를 담는 객체이다.

  • 변수
  • 매개 변수(parameter)와 인수 정보(arguments)
  • 함수 선언(함수 표현식 제외)

Variable Object는 다른 객체를 가리킨다. 하지만 전역 코드 실행 시 생성되는 전역 컨텍스트와 함수를 실행할 때 생성되는 함수 컨텍스트는 가르키는 객체가 다르다.

이유는 내용이 다르기 때문인데 대표적으로 전역 함수는 매개 변수가 없지만 함수에는 매개 변수가 존재한다.

전역 컨텍스트의 Variable Object는 전역 변수, 전역 함수 등을 포함하는 전역 객체(Global Object / GO)를 가르킨다.

함수 컨텍스트의 Variable Object는 매개 변수와 인수, 지역 변수, 내부 함수를 포함하는 활성 객체(Activation Object / AO)를 가르킨다.

Scope Chain(스코프 체인)

스코프 체인은 해당 전역 또는 함수가 참조할 수 있는 변수, 함수 선언 등의 정보를 담고 있는 전역 객체(GO) 또는 활성 객체(AO)의 리스트를 가진다.

현재 활성화 되어있는 실행 컨텍스트의 활성 객체(AO)를 선두로 순차적으로 상위 컨텍스트의 활성 객체(AO)를 가르키며 마지막 리스트는 전역 객체(GO)를 가르킨다.

함수가 중첩 상태일 때 하위 함수 내에서 상위 함수의 스코프와 전역 스코프까지 참조할 수 있는데 이것을 스코프 체인 검색을 통해서 가능하다.

함수 실행 중 변수를 만나면 그 변수를 우선 현재 Scope, 즉 활성 객체(AO)에서 검색해보고 실패하면 스코프 체인에 있는 순서대로 그 검색을 이어나간다.

전역 객체(GO)까지 검색해서 실패하면 정의되지 않은 변수에 접근하는 것으로 판단하고 Reference 에러가 발생한다.

this

this 프로퍼티는 this 값이 할당되며, this는 함수를 어떻게 호출하느냐에 따라서 결정된다.

해당 부분의 내용은 정리할 부분이 많으므로 하나의 파트로 내용을 정리해서 추후에 링크를 첨부 예정

실행 컨텍스트 생성 과정

예제 코드를 가지고 실행 컨텍스트가 어떻게 생성되는지 알아보자.

var x = 'xxx';

function foo () {
  var y = 'yyy';

  function bar () {
    var z = 'zzz';
    console.log(x + y + z);
  }
  bar();
}

foo();

전역 코드 진입

컨트롤이 실행 컨텍스트로 진입하기 이전에 전역 객체(GO)가 생성된다. 초기 상태의 전역 객체는 빌트인 객체(Math, String Array)와 BOM, DOM이 설정되어 있다.

전역 객체 생성 후 전역 코드로 컨트롤이 진입하면 전역 실행 컨텍스트가 생성되고 실행 컨텍스트 스택에 쌓인다.

그리고 아래의 순서대로 처리가 이루어진다.

  1. 스코프 체인의 생성과 초기화
  2. Variable Instantiation(변수 객체화) 실행
  3. this value 결정

스코프 체인의 생성과 초기화

실행 컨텍스트가 생성된 후 가장 먼저 스코프 체인의 생성과 초기화가 실행된다. 스코프 체인은 전역 객체(GO)를 포함하는 리스트가 된다.

변수 객체화 실행

변수 객체화는 Variable Object에 프로퍼티와 값을 추가하는 것을 의미한다. 변수, 매개 변수와 인수 정보, 함수 선언을 Variable Object에 추가하여 객체화한다.

변수 객체화는 아래의 순서대로 Variable Object에 프로퍼티와 값을 할당한다.

  1. 함수 실행 컨텍스트면 매개 변수가 프로퍼티 인수가 값으로 설정된다.
  2. 대상 코드 내의 함수 선언을 대상으로 함수명이 프로퍼티 생성된 함수가 값으로 설정된다.(함수 호이스팅)
  3. 대상 코드 내의 변수 선언을 대상으로 변수명이 프로퍼티 undefined가 값으로 설정된다. (변수 호이스팅)

위 예제 코드를 보면 변수 x와 함수 foo가 선언되었다. 변수 객체화 순서에 따르면 우선 함수 foo의 선언이 처리되고, 변수 x가 처리된다.

함수 선언 처리

변수 객체화 과정에서 전역에 선언된 함수 foo는 전역 실행 컨텍스트의 Variable Object(GO)의 프로퍼티로 함수 이름인 foo가 값으로는 생성된 함수 객체가 설정된다.

생성된 함수 객체는 [[scope]] 프로퍼티를 가지며 [[scope]] 프로퍼티는 함수 객체만 소유하는 내부 프로퍼티이다.

[[scope]] 프로퍼티는 현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 객체를 가르키며 자신을 포함하는 외부 함수의 실행 환경과 전역 객체를 가르킨다. 자신을 포함하는 외부 함수의 실행 컨텍스트가 소멸해도 [[scope]] 프로퍼티가 가르키는 외부 함수의 실행 환경은 소멸하지 않고 참조할 수 있다. 이것이 클로저 이다.

아직 코드가 실행되기 이전이며 스코프 체인이 가르키는 Variable Object에 이미 함수가 등록되어 있으므로 함수 선언문 이전에 함수 호출이 가능한 것이다.(함수 호이스팅)

변수 선언 처리

변수 선언은 아래와 같이 3가지 단계로 처리된다.

  1. 선언 단계 : 변수 객체에 변수를 등록한다.
  2. 초기화 단계 : 변수 객체에 등록된 변수를 메모리에 할당 후 값을 undefined로 초기화 한다.
  3. 할당 단계 : undefined로 초기화된 변수에 실제 값을 할당한다.

var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다. 변수 선언문 이전에 변수를 참조해도 실행 컨텍스트의 Variable Ojbect에는 참조한 변수가 undefined로 초기화가 되어있기 때문에 에러가 발생하지 않고 undefined를 반환한다.(변수 호이스팅)

this value 결정

변수 선언 처리를 끝낸 후 this value를 결정한다. this value는 전역 객체를 가르키고 있다가 함수 호출 패턴에 의해 this에 할당되는 값이 결정된다.

전역 코드의 경우에는 this는 전역 객체를 가르킨다.

전역 코드 실행

전역 코드를 실행하기 위한 준비는 끝났고 지금부터 코드가 실행된다.

var x = 'xxx';

function foo () {
  var y = 'yyy';

  function bar () {
    var z = 'zzz';
    console.log(x + y + z);
  }
  bar();
}

foo();

예제 코드의 가장 상단을 보면 x에 'xxx'를 할당하고 foo 함수를 호출한다.

변수 값의 할당

전역 변수 x에 'xxx'를 할당할 때, 현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 활성 객체(VO)를 선두부터 검색하여 변수명에 해당하는 프로퍼티가 발견되면 값을 'xxx'로 할당한다.

함수 foo 실행

함수 foo가 호출되면 컨트롤이 이동하고 함수 실행 컨텍스트가 생성된다. 이후 전역 코드와 마찬가지로 1. 스코프 체인의 생성과 초기화 2. 변수 객체화 실행, this value 결정이 순차적으로 일어난다.

스코프 체인의 생성과 초기화

활성 객체(AO)를 생성하고 스코프 체인의 선두에 설정한다. 그 후에 argument 프로퍼티 초기화를 실행하고 변수 객체화가 실행된다.

변수 객체화 실행

함수 코드인 경우에는 스코프 체인의 생성과 초기화 과정에서 생성된 활성 객체(AO)에 변수 객체화가 실행된다.

변수 y를 Variable Object에 프로퍼티는 y로 등록하고 메모리 할당 후 undefined로 값을 할당한다.

this value 결정

함수 호출 패턴에 의해 결정된 this를 결정한다. 내부 함수의 경우 this의 value는 전역 객체이다.

함수 코드 실행

변수 y에 문자열 'yyy'를 할당하고 bar 함수가 호출된다.

함수 bar 실행

bar 함수가 실행되면 컨트롤이 이동하고 실행 컨텍스트를 생성한다. 이전 함수 foo와 동일하게 1. 스코프 체인의 생성과 초기화, 2. 변수 객체화, 3. this value 결정이 동일하게 일어난다.

아래 코드의 실행 결과는 'xxxyyyzzz'가 된다.

console.log(x + y + z); 

참고
https://poiemaweb.com/js-execution-context

profile
잘 하고 싶다.

0개의 댓글