JS. 실행 컨텍스트(Execution Context)

실행 컨텍스트(Execution Context)

실행 컨텍스트는 실행 가능한 코드가 실행되기 위해 필요한 환경을 뜻한다.

브라우저(혹은 Node)는 자바스크립트를 파싱할 때 자바스크립트 엔진은 일련의 과정을 거친다. 또한 자바스크립트 엔진은 코드를 파싱하기 위해 실행에 필요한 여러 정보를 알고 있어야 한다.

전역 실행 컨테스트, 전역 Scope 생성

자바스크립트 엔진은 코드를 파싱할 때 전역 실행 컨텍스트전역 Scope를 만든다.

var x = 'xxx';

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

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

  bar();
}

foo();

위 코드를 실행하면 실행 컨텍스트에는 스택(Stack)이 생성되고 소멸한다. 현재 실행 중인 컨텍스트에서 내부 함수가 실행되면 새로운 컨텍스트가 생성된다. 함수가 호출됨에 따라 스택이 쌓이게 되고 제어권이 이동한다.

./images/ec_1.png

  1. 자바스크립트 코드를 파싱할때 전역 실행 컨텍스트가 생성되고 실행 컨텍스트 스택에 쌓인다. 전역 실행 컨텍스트는 애플리케이션이 종료될 때까지 유지된다.
  2. 함수를 호출하면 해당 함수의 실행 컨텍스트가 생성되며 직전에 실행된 코드 블록의 실행 컨텍스트 위에 쌓인다.
  3. 함수 실행이 끝나면 해당 함수의 실행 컨텍스트를 파기하고 직전의 실행 컨텍스트에 제어권을 반환한다.

호출 스택(Call Stack)이 생성

자바스크립트 엔진은 어떤 함수가 호출이 되어 일어나고 있는지 추적해야만 한다. 이를 호출 스택(Call Stack)을 통해서 수행한다.

호출 스택(Call Stack)은 현재 실행될 함수의 로그와 같다.

자바스크립트에서 실행된 함수는 스택(Stack)이라는 데이터 구조로 반환한다.

스택(Stack)

스택: 데이터 구조

스택은 LIFO(Last In First Out, 후입 선출) 구조를 가지는 나열 구조이다.


실행 컨텍스트 구조

./images/excute_context_structure.png

변수 객체(Variable Object / VO)

실행 컨텍스트가 생성되면 자바스크립트 엔진은 실행에 필요한 여러 정보들을 담을 객체를 생성한다. Variable Object는 코드가 실행될 때 엔진에 의해 참조되며 코드에서는 접근할 수 없다.

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

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

전역 컨텍스트의 경우

Variable Object는 유일하며 최상위에 위치하고 모든 전역 변수, 전역 함수등을 포함하는 전역 객체(Global Object / GO)를 가리킨다. 전역 객체는 전역에 선언된 전역 변수와 전역 함수를 프로퍼티로 소유한다.

./images/ec-vo-global.png

함수 컨텍스트의 경우

이때, Variable Object는 Activation Object(AO / 활성 객체)를 가리키며 매개변수와 인수들의 정보를 배열의 형태로 담고 있는 객체인 arguments object가 추가된다.

./images/ec-vo-foo.png

Scope Chain (SC)

스코프 체인은 리스트로서 전역 객체와 중첩된 함수의 스코프의 레퍼런스를 차례로 저장하고 있다.

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

./images/ec-sc.png

자바스크립트 엔진은 스코프 체인을 통해 Lexical Scope를 파악한다. 함수가 중첩 상태일 때 하위함수 내에서 상위함수의 스코프와 전역 스코프까지 참조할 수 있는데 이는 스코프 체인을 검색을 통해 가능하다. 함수가 중첩되어 있으면 중첩될 때마다 부모 함수의 Scope가 자식 함수의 스코프 체인에 포함된다. 함수 실행중에 변수를 만나면 그 변수를 우선 현재 Scope, 즉 AO에서 검색보고, 검색에 실패하면 스코프 체인에 담겨진 순서대로 검색을 이어가게 된다.

this

this 프로퍼티에는 this 값이 할당되는데, this에 할당되는 값은 함수 호출 패턴에 의해 결정된다. (‘무엇이 함수를 호출했는 가’에 의해)

전역 컨텍스트의 this는 window이다.

실행 컨텍스트 생성 과정

var x = 'xxx';

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

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

foo();

1. 전역 코드에 진입

실행 컨텍스트에 진입하기 이전에 유일한 전역 객체가 생성된다. 전역 객체가 생성된 이후, 전역 코드로 제어권이 진입하면 전역 실행 컨텍스트가 생성되고 실행 컨텍스트에 스택에 쌓인다.

./images/ec_4.png

위 실행 컨텍스트를 바탕으로 아래와 같은 순서로 실행된다.

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

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

스코프 체인의 생성과 초기화가 실행되고, 이때 스코프 체인은 전역 객체의 레퍼런스를 포함하는 리스트가 된다.

./images/ec_5.png

2) Variable Instantiation(변수 객체화) 실행

Variable Instantiation은 Variable Object에 프로퍼티와 값을 추가하는 것을 의미한다. 변수 객체화라고 하는데 이는 변수, 매개변수와 인수(arguments), 함수 선언을 Variable Object에 추가하여 객체화한다.

./images/ec_6.png

  1. (함수인 경우) 매개변수가 Variable Object의 프로퍼티로 인수가 값으로 설정된다.
  2. 함수 호이스팅
  3. 변수 호이스팅

2.1) 함수 foo의 선언 처리

./images/ec_7.png

생성된 함수 객체는 [[Scopes]] 프로퍼티를 가지게 된다. [[Scopes]] 프로퍼티는 함수 객체만이소유하는 내부 프로퍼티로서 함수 객체가 실행되는 환경을 가리킨다.

내부 함수의 [[Scopes]] 프로퍼티는 자신의 실행 환경(Lexical Enviroment)과 자신을 포함하는 외부 함수의 실행 환경과 전역 객체를 가리키는데 이때 자신을 포함하는 외부 함수의 실행 컨텍스트가 소멸하여도 [[Scopes]] 프로퍼티가 가리키는 외부 함수의 실행 환경(Activation object)은 소멸하지 않고 참조할 수 있다. 이를 클로저라고 한다.

./images/foo-scopes.png

2.2) 변수의 선언 처리

선언 단계: 변수 객체에 변수를 등록한다. 이 변수 객체는 스코프가 참조할 수 있는 대상이 된다. 초기화 단계: 변수 객체에 등록된 변수를 메모리(Stack)에 할당한다.이 단계에서 변수는 undefined로 초기화된다. 할당 단계: undefined로 초기화된 변수에 실제값을 할당한다.

var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다. 다시 말해 스코프 체인이 가리키는 변수 객체에 변수가 등록되고 변수는 undefined로 초기화된다. 이에 변수 선언문 이전에 변수에 접근하여도 Variable Object에 변수가 존재하기 때문에 에러가 발생하지 않는다. 다만 undefined를 반환한다. 이를 변수 호이스팅이라 한다.

./images/ec_8.png

2.3) this value 결정

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

./images/ec_9.png

전역 컨텍스트(전역 코드)의 경우, Variable Object, 스코프 체인, this 값은 언제나 전역 객체이다.


Reference

Poiemaweb : 실행 컨텍스트


Written by@Jkun
...

GitHub