IT모아

자바스크립트 Execution Context 란 본문

JavaScript

자바스크립트 Execution Context 란

아롱사태남 2017.04.18 11:31

아래 글(퍼온) 을 읽기전에 실행문맥이 생성되면 최초 효율적인 탐색을 하기 위해 스코프 체인을 형성하는줄 알았는데.

한 뎁쓰가 더 존재하였다는 사실을 알게되었다.





아래문서는 11월 28일 김영보 강사님의 "자바스크립트 중/고급 강좌"를 듣기 위한 정리로 David Shariff의 blog 문서를 정리한 것이다.

http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/

1. Execution Context?

자바스트립트가 실행될때 실행되는 환경은 매우 중요하며 다음과 같은 것으로 분류된다

        Global Code - 코드가 첫번째로 실행되는 기본환경
        Function code - Whenever the flow of execution enters a function body.
        Eval code - eval function내에서 실행되는 코드

 

위 코드는 global context 1개와 3개의 다른 function context 표현 되어 있다.

global context는 프로그램내에서 다른 컨텍스트부터 접근이 가능한 유일한 context이다.

여러개의 function context를 만들수 있으며 각각의 function context는 함수를 호출함으로 만들어진다. 이 function context는 밖에서 접근할수 없는 함수내부에 선언된 변수등의 것을 private scope로 만든다.

current context 밖에 선언된 변수들을 접근가능하다. 하지만 outside context는 안쪽에 선언된 context의 변수를 접근할수 없다.   왜 이렇게 작동하지는 다음을 보고 이해하자.


2. Execution Context Stack

  브라우저의 javascript interpreter는 single thead로 구현되어있다.

즉, 한번에 1개의 action을 할수있으며 나머지를  Execution Stack이라고 불리는 곳에 쌓이게 된다.

아래그림을 통해서 single threaded stack를 이해하자.

 

우리가 아는 것 처럼, 브라우저가 첫번째로 당신의 스크립트를 로드할때 global execution context로 들어간다.

global 코드 내에서 function를 호출하면 프로그램의 흐름은 function으로 들어가면서 새로운 execution contect를 생성하게 된다. 그 생성된 execution context는 execution stack의 최상위에 위치하게된다.

만약 현재 function에서 다른 내부 function을 호출하면  똑같은 일이 일어난다.  execution 흐름은 function안으로 들어가고 새로운 execution context를 생성하고 다시 execution stack의 최상위로 위치하게 된다.

브라우저는 항상 stack 상위에 있는 current execution context를 실행하다. 그 execution context가 완료되면 stack에서 빠져나오며 제어의 흐름을 current stack 아래의 context에게 넘겨준다.

다음 예를 통해서 이해해보자

(function foo(i) {

if(i === 3 ) {

return;

} else {

foo(++1);

}

}(0));



Execution Stack에서 기억해야할 5가지는 아래와 같다.

    단일 스레드
    동기화 실행
    1개의 Global context
    무한 function context들
    각각의 function 호출은 새로운  execution Context 생성한다.


3. Execution Context 상세
2가지 stages 로 구분된다.
     1).  Creation Stage

        변수,함수, arguments 만들어라
        Scope Chain 만들어라.
        "this"의 값을 결정해라.

    2). Activation / Code Execution Stage

        값, 함수의 참조값을 할당,  코드를 해석하고 실행

      execution context 개념적으로 3개의 프로퍼티로 나타낼수 있다.
executionContextObj = {
    variableObject: { /* function arguments / parameters, inner variable and function declarations */ },
    scopeChain: { /* variableObject + all parent execution context's variableObject */ },
    this: {}
}


4. Activation / Variable Object [AO/VO]

executionContextObj는 함수가 코드가 실행되전에 함수호출될때 만들어 진다. 이것을 creation Stage이다.

여기서, 해석기는 함수의 파라미터, 넘겨지는 argument, 로컬함수선언, 로컬변수 선언 스캔하여 executionContextObject를 만든다.  그결과로 executionContextObject의 variableObject가 된다.

브라우저 해석기가 코드를 어떻게 평가하는지 아래 내용을 보자.

1)  함수를 호출하는 코드를 찾는다.   ----- (1)

2) 함수코드가 실행되기전 execution context를 생성한다.   ----(2)

3) creation stage로 들어간다.

            variable object를 만든다.   ----(3)
                arguments object를 만든다.    ----(4)
                    파라미터에 대해서 체크, 그 파라미터 이름과 값을 초기화
                함수 선언에 대한 context를 스캔한다.
                    각 함수를 찾아서 그 이름을 가진 variable object를 만들고 메모리에 그함수를 참조 pointer를 갖도록한다.    --------- (5)
                    그 함수 이름이 존재하면 참조pointer는 overwrite 된다
                변수 선언에 대해서 context를 스캔한다.
                    선언된 변수를 찾으면  변수이름을 가진 property를 variable object에 생성하고 값을 "undefined"로 초기화 한다.   ---- (6)
                    만약 그변수의 이름이 variable object에 존재하면 아무일도 안하고 계속 스캔한다.

4) Activation / Code Execution Stage:

            context안에 있는 함수 코드를 해석하고 실해하며 한줄씩 실행되면서 변수의 값들을 할당한다.


        예제를 통해서 위의 동작들을 다시 한번 보자

  function foo(i) {
    var a = 'hello';
    var b = function privateB() {

    };
    function c() {

    }
}

foo(22);


foo(22)가 호출되면  다음과 같이 create stage 볼수있다.

fooExecutionContext = {   ------ (2)

    variableObject: {     ------(3)

        arguments: {      -------(4)

            0: 22,

            length: 1

        },

        i: 22,      ----- (4)

        c: pointer to function c()  -------(5)

        a: undefined,    ------(6)

        b: undefined    ------(6)

    },

    scopeChain: { ... },

    this: { ... }

}


위에서 보는 처럼, creation stage에서는 property의 이름을 정의하는 것을 다루며  값 할당은 안한다.(arugment/파라미터는 제외)

creation stage가 완료되면 실행의 흐름은 함수 안으로 들어가게 된다.

 Actionvation / code execution stage 단계는 아래와 같이 보일것이다. (함수 실행후)

fooExecutionContext = {

    variableObject: {

        arguments: {

            0: 22,

            length: 1

        },

        i: 22,

        c: pointer to function c()

        a: 'hello',

        b: pointer to function privateB()

    },

    scopeChain: { ... },

    this: { ... }

}


=======================================================================

위의 내용을 모두 이해 했다면 javascript에서 hoisting 에 대해서 바로 이해가 될것이다.

아래 예제를 통해서 확인해보자.  

​(function() {


    console.log(typeof foo); // function pointer

    console.log(typeof bar); // undefined


    var foo = 'hello',

        bar = function() {

            return 'world';

        };


    function foo() {

        return 'hello';

    }


}());​


    왜 우리는 foo 를 선언하기 전에 foo를 접근할수 있었을까?
        creation stage 단계에서  activation / code execution stage 전에 미리 만들어 졌음을 알수있다.
        그래서 함수코드가 실행될때 foo는 벌써 activation object에 정의 되어있었을 것이다.

    foo는 두번 선언되어있는데 왜 foo는 undefinded 또는 string으로 보여주지 않고 function으로 보여줄까?
        두번 선언되었음에도 불구하고 우리는 creation stage에서 함수가 activation object로 변수가 생성되기 전에 생성된것을 알고있다. 만약 property name 벌써 activation object로 존재한다면 선언을 그냥 넘어갈것이다.
        그러므로, function foo대한 참조는   첫번째로 activation object로 생성된다.  해석기가 var foo를 얻을 때 벌써 foo 이름 property가 존재함으로 코드는 아무것도 않고 넘어가게된다.

    왜 bar는 undefined 인가?
        bar 는 function를 할당한 변수이다. 변수는 creation stage 에서 생성되지만 그것은 undefined값으로 초기화 되어있다.

#Variable Object : 어떤 코드가 실행될 때 찾을 변수를 키와 값으로 가진 객체

#Activation Object(활성 객체) : 함수가 실행될 때 실행 문맥에 의해 생성되며, 함수 자체에 대한 변수 객체가 된다.





출처: http://smarttech.tistory.com/entry/Javascript-Execution-context와-Stack에-대해서-정리하자 []


0 Comments
댓글쓰기 폼