[Javascript] 문법의 문맥, 실행 컨텍스트


문법의 문맥(Context)

문맥어떤 주어진 언어표현이 나타나는 부분과 연관이 되는 언어적인 맥락.

실행 컨텍스트(Execution Context)

실행 컨텍스트란, 우리 말로 하자면 실행 문맥이라는 뜻 입니다. 자바스크립트의 핵심 원리중 하나이며 코드를 독해하거나, 이해하는데에 꼭 필요한 요소입니다.
사실, 문맥이라는 것은 어떤 언어에서든지 중요한 부분입니다. 그 언어가 자바스크립트라고 할지라도 말이죠. 문맥(Context)을 이해한다면 문장을 이해할 수 있고, 문장을 이해한다면 글을 이해할 수 있을 것 입니다.

먼저, 다음과 같은 코드가 있다고 생각하겠습니다.

var a = 'A'

function foo() {
  var b = 'B'

  function bar() {
    var c = 'C'

    console.log(a, b, c)
  }

  bar()
}

foo()

// 실행 결과 : A B C

위 코드는 전부 3개의 실행 컨텍스트가 만들어집니다


실행 컨텍스트 스택

execution_context_stack_diagram 3개의 실행 컨텍스트가 스택에 쌓이고, 소멸됩니다

총 3개의 실행 컨텍스트는 스택에 쌓이고, 소멸됩니다. 가장 먼저 전역 컨텍스트가 생성이 되며 실행되고, 실행하는 순간에 다른 함수(함수가 아닐 수도 있습니다)가 실행되면 또 다른 실행 컨텍스트가 스택에 쌓입니다.
이렇게 쌓여진 스택은, 나중에 들어온 것이 가장 빠르게 나가는 후입선출의 구조를 가집니다.

더 이상 쌓을 실행 컨텍스트가 없는 스택은 늦게 들어온 순서대로 활성화되어 소멸되며, 소멸되는 때에 자신(소멸된)을 실행시킨 실행 컨텍스트를 활성화 시키면서, 이 작업을 반복합니다.

실행 컨텍스트의 구조

execution_context_structure

실행 컨텍스트는 위와 같은 객체로 간단히 설명할 수 있습니다. 컨텍스트에는 위 그림과 같은 속성들(properties)이 있습니다. 이 속성들은 컨텍스트의 상태라고 할 수 있습니다.

1. 변수 객체 (Variable Object)

Variable Object는, 실행 컨텍스트에서 선언된 변수 혹은 함수(함수 표현식은 저장되지 않습니다)들을 저장합니다.

Variable Object는 추상적인 개념이지만, 다른 컨텍스트 타입에서는 물리적으로 다른 객체를 사용하여 표시됩니다. 예를 들어, 전역 컨텍스트에서는 Variable Object이 전역 컨텍스트 그 자체 입니다. 그렇기 때문에 우리는 전역 객체의 속성 이름을 통하여 전역 변수를 참조할 수 있습니다.

1.1 활성화 객체 (Activation Object)

Activation Object는, 함수 컨텍스트가 활성화(함수가 호출)될 때 만들어지는 특수 객체입니다.

이 Activation Object는 매개변수(parameter)와 전달인자(argument)로 이루어져 있습니다. 또한, Activation Object는 함수 컨텍스트(함수로 호출된 실행 컨텍스트)의 Variable Object로 사용됩니다.
즉, 함수 컨텍스트의 Variable Object는 동일하게 간단한 변수 객체이지만, 변수와 함수 이외에도 매개변수전달인자를 저장하며 Activation Object라고 합니다.

activation_object_structure

2. 스코프 체인 (Scope chain)

스코프 체인은 컨텍스트의 코드들을 검색하는 객체의 목록입니다. 만약 해당 실행 컨텍스트에 a라는 변수를 선언했고, 이를 찾고자 할 때 스코프 체인에서 검색하는 것 입니다.
이 스코프 체인에서 만약 검색에 실패했다면, 부모 컨텍스트(해당 컨텍스트를 실행시킨)에서 검색을 합니다. 그렇게 계속 반복되며 결국 전역 컨텍스트까지 올라가게 됩니다. 만약 전역 컨텍스트에서도 검색에 실패한다면, 자바스크립트 엔진은 저희에게 오류를 줄 것입니다.
위 예제 코드의 bar()에서 해당 컨텍스트(bar())에서 선언한 변수가 아니어도 쓸 수 있는 이유는 이 스코프 체인의 이 특성 때문입니다.
또한 스코프 체인은 함수의 [[scope]]를 통해 접근할 수 있습니다.

검색되는 대상은:

  • 선언된 변수명
  • 선언된 함수명
  • 매개변수
  • 등등..

3. thisValue

this는, 함수의 호출 방식에 따라 그 값이 바뀌게 됩니다. 만약, 함수가 객체를 참조해서(new Function)생성 되었다면 this는 해당 객체를 가르키게 됩니다. 이외에 경우에서는 보통 this가 글로벌 객체를 가르킵니다.

실행 컨텍스트 실행

이제 우리는 다음과 같은 코드에서 실행 컨텍스트는 어떻게 행동하는지 알 수 있습니다. 행동 패턴을 알아봅시다.

var a = 'A'

function foo() {
  var b = 'B'

  function bar() {
    var c = 'C'

    console.log(a, b, c)
  }

  bar()
}

foo()

// 실행 결과 : A B C

1. 변수 a의 할당

자바스크립트에서 변수를 선언할 때는 모두 세가지의 단계가 이루어집니다.

  1. 선언 단계

    변수 객체(Variable Object)에 변수를 등록합니다.

  2. 초기화 단계

    선언 단계에서 등록된 변수를 메모리에 할당합니다.

  3. 할당 단계

    초기화된 변수에 실제값을 할당합니다.

변수는 선언됨과 동시에 초기화가 됩니다. 선언이 된 변수명은 변수 객체에 등록되고, 이 변수 객체에 등록된 변수는 실행 컨텍스트에서 스코프 체인을 통하여 참조될 수 있습니다.
만약 변수 할당 전에 변수를 참조 한다면, 할당 단계를 거치지 않은 변수명이 변수 객체에 등록이 되어있으므로 값은 undefined가 될 것입니다. 그리고 이러한 개념을 호이스팅이라고 합니다.

다시 본론으로 돌아와, 변수 a는 다음과 같은 과정을 거쳐 전역 객체에 할당됩니다.

2. 함수 foo의 할당

함수 선언은 변수 선언과 비슷하게 변수 객체에 등록됩니다. foo라는 이름이 프로퍼티명으로 들어가고, 선언된 함수 객체가 값으로 설정됩니다.
함수 객체는 [[Scopes]]라는 프로퍼티를 가지게 됩니다. 이 프로퍼티는 함수 객체가 실행되는 환경을 저장합니다. 즉, 선언될 때의 실행 컨텍스트의 스코프 체인이 참조하고 있는 객체를 값으로 저장힙니다.
만약 선언될 때의 실행 컨텍스트가 소멸 되더라도, [[Scopes]]에 자신과 외부 함수의 실행 환경을 저장하고 있으므로, 외부 컨텍스트의 소멸에 상관없이 실행할 수 있게 되는 것 입니다. 그리고 이러한 개념을 클로저라고 합니다.

3. 함수 foo의 실행

전역 코드에 있는 foo()가 실행되면 새로운 실행 컨텍스트가 생성되고, 그 컨텍스트는 컨텍스트 스택에 쌓이게 됩니다. 그러면 원래 활성화되어 있던 전역 컨텍스트는 비활성화가 되고, 방금 생성되어 스택에 쌓인 컨텍스트가 활성화 됩니다.
이 컨텍스트가 활성화가 되면 전역 컨텍스트와 같이, 1. 변수 a의 할당과 같이 변수 b의 할당이 이루어집니다. 이때 전역 객체와 달라지는 것은 활성화 객체를 사용한다는 점일 것입니다. 활성화 객체는 매개변수와 전달인자를 저장하기 때문에 먼저 arguments(매개변수) 프로퍼티의 초기화를 실행합니다.
그 후에는 해당 컨텍스트의 스코프 체인이 참조하고 있는 객체(전역 컨텍스트)를 스코프 체인에 추가시킵니다. 만약 전역 컨텍스트가 아닌, 함수 컨텍스트라면, 전역 컨텍스트가 추가될 때 까지 이 작업을 반복하여 스코프 체인을 채웁니다.
이전 작업들과 다른 것은 활성화 객체를 사용한다는 점뿐입니다.

4. thisValue 결정

선언 처리가 모두 끝난다면 this value가 결정됩니다. 이전에 쓴 내용 처럼 this value는 함수의 호출 방식에 따라 바뀌게됩니다.
foo함수(내부 함수)의 경우 this value는 전역 객체가 됩니다.

5. 변수 b의 할당

변수 b는, 선언이 되기 전에 해당 컨텍스트의 스코프 체인에서 b라는 이름의 프로퍼티가 있는지 검색하고 만약 없다면, 선언, 초기화 단계를 거치며 활성화 객체에 할당됩니다.

6. 함수 bar의 할당

함수 bar또한, 변수 b처럼 스코프 체인에서 검색을 하고, 활성화 객체에 할당되어집니다.

7. 함수 bar의 실행

함수 bar가 실행되면, 함수 foo가 실행됐던 것 처럼 실행 컨텍스트가 스택에 쌓이고 활성화된 컨텍스트가 함수 bar의 컨텍스트로 바뀌게 됩니다.
해당 실행 컨텍스트의 스코프 체인은 bar의 활성화 객체와, 전역 객체의 변수 객체를 가지게 됩니다.

8. 변수 c의 할당

8단계는 5단계와 같이 처리됩니다.

9. console.log

이 단계에서 콘솔에는 A B C라는 문자열이 출력됩니다.

끝으로

아.. 뭔가 엉성하게 마무리된 것 같은 느낌이 드는 글이었다. 쓰는 데만 3일이 걸렸고, 다 쓰고 나서도 찝찝한 느낌이 든다… 만약 나중에 생각이 나면 글을 다시 써볼 것이다. 하지만 힘든 만큼 내가 얻는 것도 많은 글이었다고 생각하는 게, 이제 괄호를 통해서 (부연 설명)하는 방식도 어느 정도 익힌 것 같고, 강조해야 할 단어, 문장에 볼드 처리를 해주는 것 또한 미숙하게나마 익혔다. 또한 어렴풋이 알고 있던 지식에 대해 정확하게 알 수 있게 되어 개인적으로 고마운 글이라고 생각한다.

외부링크

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#execution-context




© 2019. by jong-hui

Powered by aiden