실행 컨텍스트 (Execution Context)
실행 컨텍스트란?
실행할 코드에 제공할 환경 정보들을 모아놓은 객체로서, JavaScript 의 동적언어의 성격을 가장 잘 나타내는 개념이다.
JavaScript 는 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고(호이스팅의 개념), 외부 환경 정보를 구성하고, this 값을 설정하는 등의 동작을 수행한다.
실행 컨텍스트라는 개념을 이해하는 것은 개발자의 성장으로서 가장 중요한 핵심이니 꼭 이해하고 넘어가도록 하자.
실행 컨텍스트를 이해하기 전 스택(stack) 과 큐(queue) 의 개념부터 살펴보자.
스택(stack) 은 출입구가 하나뿐인 깊은 우물같은 데이터 구조이다.
비어있는 스택에 순서대로 데이터 a, b, c, d 를 저장한 후 꺼낼 때에는 반대로 d, c, b, a 순서로 꺼낼 수 밖에 없다.
4개만 저장할 수 있는 우물에 4개 이상을 저장하면 넘치게되는 것을 overflow 라고 한다. (스택오버플로우라는 사이트가 생각난다)
큐(queue) 는 양쪽이 모두 열려있는 파이프이다.
비어있는 큐에 순서대로 데이터 a, b, c, d 를 저장했다면 꺼낼때에도 a, b, c, d 순서대로 꺼낼 수 밖에 없다.
앞서 언급했듯이, 실행 컨텍스트를 실행할 코드에 제공할 환경 정보들을 모아놓은 객체라고 했는데,
동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고, 이를 콜 스택(Call Stack)에 쌓아올렸다가,
가장 위에 쌓여있는 컨텍스트와 관련이 있는 코드들을 실행하는 방식으로 전체 코드의 환경과 순서를 보장한다.
동일한 환경이란 쉽게 설명하자면, 하나의 실행 컨텍스트를 구성할 수 있는 방법으로 전역공간, eval함수, 함수 등이 있다.
우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것뿐이다.
예제 코드를 통해 확인해보자.
var a = 1;
function outer() {
function inner() {
console.log(a); // undefined
var a = 3;
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
최상단의 공간은 코드 내부에서 별도의 실행 명령이 없이도 브라우저에서 자동실행하므로 JavaScript 파일이 열리는 순간 전역 컨텍스트가 활성화된다고 이해하면 된다.
위 코드를 그림으로 이해해보자.
콜 스택에는 전역 컨텍스트 외에 다른 덩어리가 없으므로 전역 컨텍스트와 관련된 코드가 순차적으로 진행되다가 outer 함수를 호출하면 JavaScript 엔진은 outer 에 대한 환경정보를 수집하여 outer 실행 컨텍스트를 생성한 후 콜 스택에 담는다.
콜 스택의 맨 위에 outer 실행 컨텍스트가 놓인 상태가 되었으므로 전역 컨텍스트와 관련된 코드의 실행을 일시중단하고 outer 실행 컨텍스트와 관련된 코드들을 순차 실행한다.
순차적으로 진행한 후, 콜 스택에 아무것도 남지 않은 상태가 되면서 종료된다.
스택 구조를 생각해보면 한 실행 컨텍스트가 콜 스택의 맨 위에 쌓이는 순간 곧 현재 실행할 코드에 관여하게 되는 시점임을 알 수 있다.
어떤 실행 컨텍스트가 활성화될 때 JavaScript 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는 데 필요한 환경 정보들을 수집하여 실행 컨텍스트에 저장한다.
이 객체는 JavaScript 엔진이 활용할 목적으로 생성할 뿐 개발자가 코드를 통해 확인할 수는 없다.
이 곳에 담기는 정보는 아래와 같다.
- VariableEnvironment : 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경정보. 선언 시점의 LexicalEnvironment 의 스냅샷으로 변경사항은 반영되지 않는다.
- LexicalEnvironment : 처음에는 VariableEnvironment 와 같지만 변경 사항이 실시간으로 반영된다.
- ThisBinding : this 식별자가 바라봐야할 대상 객체로, VariableEnvironment 와 LexicalEnvironment 내부에 environmentRecord 와 outer-EnvironmentReference 로 구성되어 있다.
environmentRecord 에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장된다.
컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우 그 함수의 자체, var 로 선언된 변수의 식별자등이 해당된다. 컨텍스트 내부 전체를 처음부터 끝까지 쭉 훑어나가며 순서대로 수집한다.
호이스팅의 규칙
environmentRecord 에는 매개변수의 이름, 함수, 선언, 변수명 등이 저장된다.
이번에도 예제 코드를 살펴보자.
function a (x) {
console.log(x); // (1)
var x;
console.log(x); // (2)
var x = 2;
console.log(x); // (3)
}
a(1);
호이스팅이 되지 않았을 때, 위 코드에 어떤 값들이 출력되는지 예상해보자.
function a () {
var x;
var x;
var x;
x = 1;
console.log(x); // 1
console.log(x); // 1
x = 2;
console.log(x); // 2
}
a(1);
호이스팅을 마친 상태의 코드다.
함수 선언문과 함수 표현식
함수 선언문이란, function 정의부만 존재하고 별도의 할당 명령이 없는 것이고, 함수 표현식은 정의한 function 을 별도의 변수에 할당하는 것이다.
function a () {/* ... */ } // 함수 선언문. 함수명 a가 곧 변수명
a(); // 실행 OK
var b = function () {/* ... */ } // (익명) 함수 표현식. 함수명 b가 곧 변수명
b(); // 실행 OK
var c = function d () {/* ... */ } // 기명 함수 표현식. 변수명 c, 함수명 d
c(); // 실행 OK
d();
다음은 this 에 대해 공부해보자.
* 출처 : '코어 자바스크립트 - 핵심 개념과 동작 원리로 이해하는 자바스크립트 프로그래밍', 정재남 지음
'Front-End > JavaScript' 카테고리의 다른 글
[JavaScript] 콜백 함수 (Callback Function) (1) | 2020.04.04 |
---|---|
[JavaScript] this 파헤치기 (0) | 2020.03.28 |
[JavaScript] 데이터 타입(기본형과 참조형) (0) | 2020.03.16 |
[JavaScript] null 과 undefined (0) | 2019.05.13 |
[JavaScript] Symbol 객체 (0) | 2019.05.13 |
최근댓글