2015년 3월 8일 일요일

[JavaScript] 실행 영역(Execution Context)과 스코프(Scope)

자바스크립트는 타 프로그래밍 언어에 비해 조금더 융통성있는 특별한 실행 영역(Execution Context)과 스코프(Scope)를 가지고 있다. 이로 인해 함수(Function)은 다양한 영역(Context)에서 호출될 수 있고, 그러한 스코프(Scope) 생성하고 유지할 수 있다. 이러한 컨셉은 "Closure"와 같은 특별한 디자인 패턴(Design Pattern)을 자바스크립트에서 구현 가능할 수 있게 만들었다

Execution Context(실행 영역)


흔히들 Context 라 부르기도 하는 Execution Context(실행 영역)는 스크립트가 실행되면서 생성(Global Context)되거나 Function Call에 의해 생성(Active Context) 되게 된다. 각각의 활동 컨텍스트(Active Context)들은 Function Call에 의해 생성되며 생성된 순서대로 Stack 메모리에 된삽입되게 되고, Stack의 FILO 원리대로 현재 실행중인 Context는 Stack의 최상위에 위치하게 된다. 각각의 Context는 언제나 1개의 변수 환경(Variable Environment), 1개의 Lexical Environment, 그리고 1개의 ThisBinding 속성, 총 3개의 부분으로 구성되 있다. 그리고 3 속성 모두 Object 형식으로 저장된다(자바스크립트의 Object 자료형으로 저장되는게 아니다. 그러니 사용자가 Access 할 방법은 전혀 없다).

Lexical Environment Object

한글로 번역(의역)하자면 "구성 환경 객체"이라고 할 수 있겠다. 해당 Context에서 서언된 변수/함수들의 Reference 값을 저장하는 객체이다.(내부 구성은 Variable Environment Object 에 저장된다). Identifiers(변수/함수이름)을 Reference(메모리 참조값)으로 변환할 때 사용된다. Execution Context의 생성 초기시점에는 아래에서 설명할 Variable Environment Object와 정확히 같은 값을 가지나, Context 내부에서 Scope Augmentation이 실행될 시, Variable Environment Object와는 달리 새로운 Identifier 와 그의 Reference 값이 추가된다.

Variable Environment Object

한글로 번역(의역)하자면 "변수 환경 객체"이라고 할 수 있다. 사실 변수 환경 또한 Lexical Environment(구성 환경)에 포함되는 개념이나, 위에서 설명한 Lexical Environment Object가 생성 후에 내부 값이 변할 수 있는 것과 달리
Variable Environment Object는 내부에서 선언된
  • 변수(Variables)
  • 함수 선언(Function Declarations)
  • 함수 매게 변수(Formal Parameters)
들을 저장하기 때문에 Hoisting등 this 키워드를 이용한 Expression에 의해 새로운 변수/함수가 등장하더라도 절대로 값이 변하지 않는다.

ThisBinding Object

ThisBinding 객체는 해당 Execution Context의 this 키워드의 반환 값을 저장한다.
Execution Context에서 사용자가 유일하게 접근(Access)가능한 부분이다. 참고로 this 키워드는 현재 Context가 참조하고 있는 객체를 가리키며 이 값은 어떻게 함수가 호출되었냐에 따라 갈린다

당연하겠지만, Execution Context 내부의 모든 코드가 실행이 완료된 후에는, Execution Context는 Stack에서 삭제되며, 그와 관련된 Lexical Environment Object, Variable Environment Object, ThisBinding Object 모든 구성 환경 값들 또한 삭제된다.

Global Context는 최상위이자 가장 밖의 Execution Context로 function 외부에서 선언된 모든 함수들과 변수들이 이에 포함된다.

웹 브라우져 환경에서 Global Context의 Variable Environment Object는 Window Object이며체, Global Context에서 선언된 함수들과 변수들은 모두 Window Object에 저장된다.이 Execution Context 내부의 모든 코드가 실행이 되고 난 후에는, Window Object에서 삭제되고, 그 안에 저장된 함수들과 변수들 또한 파괴된다.
Window Object 위의 Global Context는 웹페이지가 종료 되고 난 후에야 파괴된다.

Execution Context의 Variable Environment Object는 아래와 같은 형식으로 저장된다.


var a = "글로벌";
var b = 33;

function demo(x) {
  var c = "함수 컨텍스트";
};

demo(20);


위와 같은 자바스크립트 코드는 아래와 같은 Variable Object(변수 객체)를 가지게 된다.


// Variable object of the global context
변수객체(Global Context, 글로벌 컨텍스트) = {
//(웹브라우져 환경에서는 Global Context의 변수 객체가 Window Object이다)
  a: "글로벌",
  b: 33,
  demo: -> demo 함수가 저장된 메모리 주소
};
  
// Variable object of the "test" function context
VO(demo Function Context, 함수 내부의 컨텍스트) = {
  x: 20,
  c: "함수 컨텍스트"
};


Variable Scope(변수 스코프)


흔히들 스코프라 부르는게 바로 Variable Scope이다. Variable Scope는 변수에 접근이 가능한 유효 범위를 뜻한다. 즉 Variable(변수), Function(함수), 그리고 formal parameter(매게 변수)의 접근성과 생존 기간를 말하는 개념이다. Scope 은 Execution Context와 Execution Context의 Lexical Environment 개념과 긴밀한 관계에 있기 때문에, 위의 Execution Context를 잘 이해했다면 Scope도 쉽게 이해할 수 있다.

Scope은 크게 Global Scope 과 Local Scope, 두가지 종류로 나뉘는데, 이 중 Global Scope은 스크립트 실행시 생성되는 Execution Context의 Scope이고, local scope은 function 호출시 생성되는 Execution Context의 scope이다. 참고로 Scope은 if, for 문 같은 블럭에서는 생성되지 않고 오직 function 단위로만 생성된다. 하지만 with 문, 또는 try-catch 문으로 scope을 변경 할 수 있다.


function calculation() {
    var numToAdd = 3;
    var numToSubtract = 1;

    add();
    subtract();

    function add() {
 number = number + numToAdd;
    }

    function subtract() {
 number = number - numToSubtract;
    }
}

var number = 0;

calculation();

console.log(number); // 2
console.log(numToAdd); // 에러
console.log(numToSubtract); // 에러


위의 예제를 보자. 위 코드에서 함수 calculation()은 총 2개의 Variable Environment Object에 접근이 가능하다. 바로 본인의 context 와 연관된 variable environment object와, 본인의 상위 context인 global context의 variable environment object. 그리고 calculation() 함수 내부에서 선언된 함수들인 add 와 subtract는 각각 3개의 Variable Environment Object에 접근이 가능하다. 본인의 것, 그리고 2개의 상위 context의 것들.

이러한 이유로, number 라는 변수, numToAdd, numToSubtract라는 변수는 calculation 함수 내부뿐만이 아니라, add와 subtract함수에서도 접근이 가능해진다. 하지만 calculation 함수의 실행이 끝난 후, 즉 함수에서 벗어난 이후에는 함수의 context의 variable environment object에 접근이 불가능하다. 이러한 이유로 우리는 calculation 함수의 실행이 끝난후에 numToAdd 와 numToSubtract 함수에 접근할 수가 없게 된다.

반대로 함수의 실행이 끝나기 전이나 가장 최근 호출된 함수가 계속 사용될 경우, 즉 함수가 자신의 상위 Execution Context를 참조하고 있는 동안에는 Execution Context는 절대로 파기되지 않는다. 바로 이 점을 이용해 자바스크립트에서 Closure라는 기법을 사용할 수 있게 된다.

이게 바로 Variable Scope, 변수 유효 범위이다.

댓글 2개:

  1. 정말 이해가 잘 되게 설명해주셨네요. 감사합니다!

    답글삭제
  2. 안녕하세요. 좋은글 잘 읽었습니다. ^^
    괜찮으시다면 제 개인 git-pages 블로그에 발췌해도 괜찮을까요?

    답글삭제