본문 바로가기
Javascript

[Javascript] Javascript의 실행 컨텍스트와 스코프

by parkjp 2017. 8. 30.

 

 

1. 자바스크립트의 실행 컨텍스트 (Execution context)

 

 

 기존 언어를 경험한 사람이라면, 콜 스택을 들어보았을 것이다. 이는 함수를 호출할 때 해당 함수의 호출 정보가 차곡차곡 쌓여있는 스택을 의미한다. 실행 컨텍스트는 콜 스택에 들어가는 실행 정보 하나와 비슷하다.

 

 ECMAScript에서는 실행 컨텍스트를 "실행 가능한 코드를 형상화하고 구분하는 추상적인 개념"으로 기술한다. 이를 콜 스택과 연관지어 정의하면, "실행 가능한 자바스크립트 코드 블록이 실행되는 환경"이라고 할 수 있다. ECMAScript에서는 실행 컨텍스트가 형성되는 경우를 세 가지로 규정하고 있는데 전역 코드, eval() 함수로 실행되는 코드, 함수 안의 코드를 실행할 경우이다. ECMAScript에서는 실행 컨텍스트의 생성을 다음과 같이 말한다.

 

"현재 실행되는 컨텍스트에서 이 컨텍스트와 관련 없는 실행 코드가 실행되면, 새로운 컨텍스트가 생성되어 스택에 들어가고 제어권이 그 컨텍스트로 이동한다."

 

다음은 이에 대한 예제이다.

 

console.log("Global Context");

function context1() {
console.log("context1");
}

function context2() {
context1();
console.log("context2");
}

context2();

출력 결과

 

Global Context

context1

context2

 

 

 

 위 그림과 같이 전역 컨텍스트가 먼저 실행된다. 이 과정에서 새로운 함수 호출이 발생하면 새로운 컨텍스트가 만들어지고 실행되며, 종료되면 반환된다.

 

 

2. 실행 컨텍스트 생성 과정

 

A. 활성 객체의 생성

 

 실행 컨텍스트가 생성되면 자바스크립트 엔진은 해당 컨텍스트에서 실행에 필요한 여러 가지 정보를 담을 객체를 생성하는데 이것을 활성 객체라고 한다. 또한 이것은 엔진 내부에서만 접근 가능하고, 사용자가 접근하지는 못한다.

 

 다음 단계에서는 argument 객체를 생성한다. 여기서 arguments 객체는 함수를 호출할 때 넘긴 인자들이 배열 형태로 저장되어진 객체이다. 앞서 만들어진 활성 객체는 arguments 프로퍼티로 이 arguments 객체를 참조한다. 다음 그림은 함수에 param1과 param2가 들어왔을 경우의 활성 객체의 상태이다.

 

 

B. 스코프 정보 생성

 

 현재 컨텍스트의 유효 범위를 나타내는 스코프 정보를 생성한다. 이 스코프 정보는 현재 실행 중인 실행 컨텍스트 안에서 연결 리스트와 유사한 형식으로 만들어진다. 이 리스트로 현재 컨텍스트의 변수뿐 아니라, 상위 실행 컨텍스트의 변수도 접근이 가능하다. 이 리스트를 스코프 체인이라고 하는데, [[scope]] 프로퍼티로 참조된다. 현재 생성된 활성 객체가 스코프 체인의 가장 앞에 추가된다.

 

 현재 실행되는 실행 컨텍스트 내부에서 사용되는 지역 변수의 생성이 이루어진다. ECMAScript에서는 생성되는 변수를 저장하는 변수 객체를 언급하는데, 실제적으로 앞서 생성된 활성 객체가 변수 객체로 사용된다.

 

 변수 객체 안에서 호출된 함수 인자는 각각의 프로퍼티가 만들어지고 그 값이 할당된다. 만약 값이 넘겨지지 않았다면 undefined가 할당된다.

 

다음은 그에 대한 예제이다.

function ex(param1, param2) {
var a = 1, b = 2;
function innerEx() {
return a + b;
}
return param1 + param2 + innerEx();
}
ex(3, 4);

 

 위 그림을 보면 ex() 함수 안에 정의된 변수 a, b와 함수 innerEx가 생성된다. 여기서 주의할 점은 이 과정에서는 변수나 내부 함수를 단지 메모리에 생성하고, 초기화는 각 변수나 함수에 해당하는 표현식이 실행되기 전까지는 이루어지지 않는다는 점이다. 따라서 변수 a와 b에는 먼저 undefined가 할당된다. 표현식의 실행은 변수 객체 생성이 다 이루어진 후 시작된다. 마지막 단계에서는 this 키워드를 사용하는 값이 할당된다. 여기서 this가 참조하는 객체가 없으면 전역 객체를 참조한다.

 

이렇게 실행 컨텍스트가 생성 되고 변수 객체가 만들어진 후에 여러 가지 표현식 실행이 이루어진다. 실행이 되면서 변수의 초기화 및 연산, 또 다른 함수의 실행 등이 이루어진다.

 

참고로 전역 실행 컨텍스트는 arguments 객체가 없으며, 전역 객체 하나 만을 포함하는 스코프 체인이 있다. ECMAScript에서 언급된 바에 의하면 실행 컨텍스트가 형성되는 세 가지 중 하나로서 전역 코드가 있는데, 이 전역 코드가 실행될 때 생성 되는 컨텍스트가 전역 실행 컨텍스트이다. 전역 실행 컨텍스트는 변수를 초기화하고 이것의 내부 함수는 일반적인 탑 레벨의 함수로 선언된다. 그리고 전역 실행 컨텍스트의 변수 객체가 전역 객체로 사용된다.

 

* 브라우저에서의 최상위코드 -> 전역 코드

 

var a = 1;

b = 3;

console.log(window.a); // 1

console.log(window.b); // 3

 

** Node.js에서 최상위코드는 브라우저와 달리 전역 코드가 아니다.

Node.js에서는 하나의 파일이 하나의 모듈로 동작하기 때문에 이 파일의 최상위에 변수를 선언해도 그 모듈의 지역 변수가 된다. 하지만 var를 사용하지 않았을 경우 전역 객체인 global에 들어간다. ( 전역 객체를 오염시키는 원인이므로 주의한다. )

 

var a = 1;

b = 3;

console.log(global.a); // undefined

console.log(global.b); // 3

 

 

3. 스코프 체인

 

- 각 함수 객체는 [[scope]] 프로퍼티로 현재 컨텍스트의 스코프 체인을 참조한다.

- 한 함수가 실행되면 새로운 실행 컨텍스트가 만들어지는데, 이 실행 컨텍스트는 자신이 사용할 스코프 체인을 현재 실행되는 함수 객체의 [[scope]] 프로퍼티를 복사하고, 새롭게 생성된 변수 객체를 해당 체인의 제일 앞에 추가하여 만든다.

 

** 스코프 체인 = 현재 실행 컨텍스트의 변수 객체 + 상위 컨텍스트의 스코프 체인

 

스코프 체인에 대한 예제이다.

 

var val = "value1";

function getVal() {
return val;
}

function printFunc(func) {
var val = "value2";
console.log(func());
}

printFunc(getVal);

 

각 함수 객체가 처음 생성될 때 [[scope]]는 전역 객체의 [[scope]]를 참조한다.

 

 

 

getVal 실행 컨텍스트에서 value 변수를 전역 객체에서 찾으므로 결과값은 "value1"이 된다.

 

 

 

 

 

참조 저서 : 송형주, 고현준, 인사이드 자바스크립트, 한빛미디어, 139쪽

 

반응형