실행 컨텍스트
실행 컨텍스트(Excution Context)란 자바스크립트가 실행할 코드에 제공할 환경 정보들을 모아놓은 객체, 실행 환경이라고 한다.
자바스크립트(JavaScript)의 this 값의 결정, 호이스팅(hoisting), 스코프 체인 등과 같은 개념을 파악할 수 있다.
실행 컨테스트는 3가지로 구분할 수 있다.
자바스크립트가 실행
될때 가장 먼저 생성되고 페이지가 종료될 때까지 유지된다.
자바스크립트 파일 하나에 단 하나만 존재 할 수 있으며, 이는 자바스크립트가 싱글 스레드인것과 관련이 있다.
함수가 호출(실행)
될 떄마다 생성되고 종료될 때 사라지는 컨텍스트이다.
eval 함수가 호출(실행)
될 때 생성되는 실행 컨텍스트이다.
eval은 특별한 함수에 속하며, 문자열로 표현된 자바스크립트 코드를 동적으로 실행할 수 있게 해준다. 현재는 속도, 보안의 문제로 거의 사용하지 않는다고 한다.
실행 컨텍스트의 생성시점에 주목해보자면, 모두 실행
될 때 생성된다는 것이다.
자바스크립트의 함수가 선언되는 곳에서 생성되는 것이 아니라 실행(호출)되는 곳에서 컨텍스트가 생성된다.
선언과 호출을 따로 생각하며 이해해야한다.
실행 컨텍스트는 다음의 순서에 따라 동작한다.
자바스크립트가 실행되면 전역 실행 컨텍스트가 생성된다.
그 이후 함수가 실행될 때마다 함수 실행 컨텍스트도 생성된다.
컨텍스트가 생성되면 변수들의 정보를 담는 변수객체, 스코프 체인, this로 구성된다.
이제 코드를 본격적으로 실행한다.
함수가 실행될 때 사용되는 변수들은 변수 객체 안에서 값을 찾는다.
변수 객체 안에 없으면 스코프 체인을 따라서 변수를 찾아나간다.
실행이 완료된 컨텍스트는 사라진다.
(단, 클로저는 사라지지 않는다.)
자바스크립트 페이지가 종료되면 전역 컨텍스트도 사라진다.
실행 컨텍스트의 내부구조는 어떻게 구성되는지 알아보자.
전역 실행 컨텍스트는 자바스크립트가 실행되면 생성된다.
자바스크립트 엔진이 이를 단순히 스캔하며 코드를 컴파일한다.
활성 객체는 자바스크립트의 모든 변수, 함수 인자, 함수 선언 정보를 담고 있는 특별한 객체이다.
실행 컨텍스트 내부에는 스코프 체인이라는 개념이 생성된다.
스코프 체인은 여러 변수 객체를 사슬처럼 연결한 리스트다.
스코프 체인은 아래의 순서로 변수 정보를 찾아간다.
현재 실행중인 함수 --> 부모 --> ... --> 전역 스코프
스코프 체인 이후에 자바스크립트 엔진은 this 값이 정해진다.
this는 실행중에 다음의 규칙에 따라서 정해진다.
a = 1;
var b = 2;
cFunc = function(e) {
var c = 10;
var d = 15;
a = 3
function dFunc() {
var f = 5;
}
dFunc();
}
cFunc(10);
위의 예제코드를 통해 실행 컨텍스트를 제대로 알아보자.
출처: https://medium.com/@happymishra66/execution-context-in-javascript-319dd72e8e2c
생성과 실행 두가지 단계로 나누어서 보자.
브라우저에서 자바스크립트가 로드되면, 엔진이 이를 실행한다.
처음에는 코드를 분석하고, 변수와 함수의 선언을 수집해 실행 컨텍스트를 준비한다(아직 실행은 하지 않았다).
실행 컨텍스트가 생성되고 초기화되며, 변수와 함수의 선언이 실행 컨텍스트에 등록된다.
이제 위의 설명에 따라 1번째 줄부터 과정을 살표보자.
1번째 줄에서는 선언이 없다. 할당만이 존재하므로 엔진은 이를 처리하지 않고 넘어간다.
2번째 줄에서는 변수의 선언이 있다. 엔진은 변수의 이름을 키에 등록하고, 실행하지 않았으므로 할당을 진행하지 않는다. 그러므로 현재 변수 b는 undefined이다.
5번째 줄에서는 엔진이 function 선언을 발견한다. function를 heap 메모리에 저장하고 메모리 위치를 가리키는 포인터를 생성한다. 함수의 내용이 무엇인지 알지는 못한다.
마지막 18번째 줄에서는 선언이 아니므로 엔진은 이를 실행하지 않는다.
globalExecutionContextObj = {
activationbj: {
argumentObj : {
length:0
},
b: undefined,
cFunc: 메모리 주소
},
scopeChain: [전역 컨텍스트],
this: window
}
생성을 끝내개 되면 엔진은 이제 실행 단계로 돌입한다.
이곳에서는 함수들을 다시한번 스캔하고 변수 값을 업데이트하고 코드를 실행한다.
1번째 줄에서는 할당 밖에 존재하지 않았는데 엔진은 컨텍스트 변수객체 속성에서 찾지 못해 추가하고 할당한다.
3번째 줄에서는 할당이 이루어져 undefined 대신 2라는 값이 들어간다.
5번째 줄에서는 함수가 할당된다.
18번쨰 줄에서는 함수가 호출된다. 엔진은 cFunc를 호출하고. 전역 컨텍스트 내부에 함수 컨텍스트를 생성한다.
globalExecutionContextObj = {
activationbj: {
argumentObj : {
length:0
},
b: 2,
cFunc: function(){},
a: 1
},
scopeChain: [전역 컨텍스트],
this: window
}
cFunc는 매개변수 e를 가지고 있어 엔진이 이를 실행 컨텍스트에 추가하고, e 라는 속성을 생성하고 값을 2로 초기화한다.
6번째 줄은 cFunc의 활성화 객체에서 c가를 컨텍스트의 변수객체 속성에 추가하고 값을 undefined로 초기화한다.
7번째 줄은 6번쨰 줄과 동일하게 작동해 d를 추가하고 undefined로 초기화한다.
9번째 줄은 선언이 아니므로 넘어간다.
11번째 줄은 함수 선언을 찾아 이를 메모리 힙에 저장하고 dFunc 속성을 생성한다. dFunc가 저장된 위치를 가리키고, 내부 내용은 알지 못한다.
cFuncExecutionContextObj = {
activationbj: {
argumentObj : {
0: e,
length:1
},
e: 10,
c: undefined,
d: undefined
dFunc: 메모리 주소,
},
scopeChain: [cFunc 함수 컨텍스트, 전역 컨텍스트],
this: window
}
6, 7번째 줄은 각각 c와 d에 10과 15를 할당한다.
9번째 줄의 a에 할당하기위해 현재 스코프에서 찾고 없으므로 바깥의 스코프로가서 찾아 할당한다.
11번째 줄은 dFunc 속성과 힙 메모리 주소를 매치한다.
cFuncExecutionContextObj = {
activationbj: {
argumentObj : {
0: e,
length:1
},
e: 10,
c: 10,
d: 15
dFunc: 메모리 주소,
},
scopeChain: [cFunc 컨텍스트, 전역 컨텍스트],
this: window
}
dFunc도 마찬가지로 f를 선언하고 실행단계에서 할당한다.
dFunc의 실행을 끝으로 cFunc는 종료되고 JavaScript는 종료된다.
그림으로 간단하게 나타나면 다음과 같이 실행 컨텍스트 Stack에 쌓이고 화살표로 스코프 체인을 형성한다.