실행 컨텍스트란?
작성한 코드를 실행하기 위해서 자바스크립트 엔진은 코드 실행을 위한 여러 정보들을 알고 있어야 한다. 선언한 변수, 함수와 같은 식별자, 변수의 유효범위(스코프), this와 같은 정보들이 있다.
즉, 실행 컨텍스트는 코드가 실행 되기 전에, 작성한 코드를 실행하기 위해 필요한 정보들을 가진 범위를 추상화, 형상화하고 구분하여 객체 형태로 나타낸 것을 말한다.
자바스크립트 엔진이 코드 실행을 위해 필요로 하는 정보들
- 변수
- 함수
- 변수의 유효범위
- this
먼저 알아두어야 하는 실행 컨텍스트의 종류
global execution context(전역 실행 컨텍스트)
기본 실행 컨텍스트로 함수 내부에 없는 코드들은 global execution context에서 실행된다.
이 과정에서 전역 객체인 1)window object가 생성된다. 그리고 이때 2)this가 window객체를 가리킨다.
function execution context(함수 실행 컨텍스트)
자바스크립트 엔진은 함수가 호출 될 때마다 호출된 함수를 위한 execution context를 생성한다. 그리고 모든 함수는 호출되는 시점에 자신만의 execution context를 가진다.
또한, 자바스크립트 엔진은 코드를 실행하기 위해 처음 한 번만 global execution context를 생성하고 함수는 호출될 때마다 함수를 위한 execution context를 생성한다.
eval function execution context
eval 함수 내에서 실행되는 코드도 함수이기 때문에 실행 컨텍스트를 갖는다. 하지만 보안상의 이유로 eval은 잘 사용되지 않는다고 한다.
call stack(호출 스택)
call stack은 코드가 실행되면 execution context를 저장하는 곳이다. 기본적으로 LIFO(last in, first out)의 구조 형태이다. 자바스크립트 엔진은 코드가 실행되면 global execution context를 생성하고 이를 call stack에 먼저 push한다. 그리고 함수가 호출되면 function execution context를 생성하고 이를 다시 call stack에 저장된 global execution context 위에 저장한다.
그 다음에, 해당 함수가 종료되면 call stack에서 함수가 제거되고, 코드를 작성한 순서대로 그 다음에 호출되는 함수가 있다면 그 함수가 call stack에 저장된다.
다음의 코드가 call stack에서 저장되고 제거되는 과정을 그림으로 살펴보자!
var x = 'x';
function foo(){
var y = 'y';
function bar(){
var z = 'z';
console.log(x+y+z);
}
bar();
}
foo();
결론
자바스크립의 엔진은 코드가 실행될 때, global execution context를 call stack에 저장되고 작성한 코드를 위에서부터 순서대로 읽으면서 funciton 호출을 만날 때마다 function execution context를 call stack에 추가하고 제거하는 과정을 거친다.
엔진이 실행 컨텍스트를 관리하고 저장하는지는 알았는데, 실행 컨텍스트는 어떻게 생성되는지도 같이 알아야 한다.
크게 Creation과 Execution phase로 나뉜다.
실행 컨텍스트는 생성 단계에서 먼저 생성이 되는데, 이때 두 가지가 일어난다.
1) Lexical Environment
2) Variable Environment 가 생성된다.
lexical Environment
함수와 변수와 같은 식별자를 정의하는데 사용하는 객체라고 생각하는 게 좋다. 다른 정의는 머리가 아주 아팠다..
다시, lexical environment에는 3가지 구성요소가 있다.
1) Environment Records
2) Reference to the outer environment
3) this binding
Variable environment
lexical environment와 기본적으로 같지만, var로 선언된 변수만 저장한다. 그외의 나머지인 let과 const, 함수 선언은 모두 lexical environment에 저장된다.
이 페이즈에서 마침내, 변수의 선언에 대한 값 할당과 함께 코드가 실행된다.
예제와 함께 살펴보도록 하자!
let a = 20;
const b = 30;
var c;
function x(e, f){
var g = 20;
return e * f * g;
}
c = x(1, 2);
Execution phase에서 실행되는 동안 각각의 변수에 실제 지정한 값들이 할당된다.
x함수가 호출되면
다시 함수 실행 컨텍스트가 execution phase에 들어오면서 변수에 지정한 값들이 할당된다.
함수 실행이 완료되면 반환된 값을 내부에 저장하고 반환된 내부 값이 global lexical environment에 업데이트 되고 callstack에서 해당 함수들이 제거된다.