Search
Duplicate

Execution Context

1. 실행 콘텍스트, 실행콘텍스트 상태 컴포넌트

실행 콘텍스트

Execution Context
함수가 실행되는 영역이자 묶음
함수 코드를 싱행하고 실행결과를 저장합니다.
스펙상의 사양
function music(title){ var musicTitle = title; }; music("음악");
JavaScript
복사
music("음악")으로 함수를 호출하면
엔진은 실행 콘텍스트를 생성하고 실행 콘텍스트 안으로 이동합니다.
실행 콘텍스트 실행 단계
준비 단계, 초기화 단계, 코드 실행 단계

실행 콘텍스트

Execution Context 생성 시점
실행 가능한 코드를 만났을 때
실행 가능 코드 유형
함수 코드, 글로벌 코드, eval 코드
코드 유형을 분리한 이유
실행 콘텍스트에서 처리 방법과 실행 환경이 다르기 때문입니다.
함수 코드: Lexical Environment
글로벌 코드: Global Environment
eval 코드: Dynamic Environment

실행 콘텍스트 상태 컴포넌트

실행 콘텍스트 상태를 위한 오브젝트
실행 콘텍스트 안에 생성
상태 컴포넌트 유형
렉시컬 환경 컴포넌트(LEC):
Lexical Environment Component
변수 환경 컴포넌트(VEC):
Variable Environment Component
this 바인딩 컴포넌트(TBC):
This Binding Component
실행 콘텍스트(EC):{ 렉시컬 환경 컴포넌트(LEC):{ }, 변수 환경 컴포넌트(VEC):{ }, this 바인딩 컴포넌트(TBC):{ } }
JavaScript
복사

2. 렉시컬 환경 컴포넌트, 렉시컬 환경컴포넌트 구성/설정 외부 렉시컬 환경 참조, 변수 환경 컴포넌트

렉시컬 환경 컴포넌트

함수와 변수의 식별자 해결을 위한 환경 설정
함수 초기화 단계에서 해석한 함수와 변수를 {name: value}형태로 저장합니다.
이름으로 함수와 변수를 검색할 수 있게 됩니다.
함수 밖의 함수와 변수 참조 환경 설정
함수 밖의 함수와 변수를 사용할 수 있게 됩니다.

렉시컬 환경 컴포넌트 구성

렉시컬 환경 컴포넌트 생성
function, with, try-catch에서 생성됩니다.
컴포넌트 구성
환경 레코드 ER: Environment Record
외부 렉시컬 환경 참조
OLER: Outer Lexical Environment Reference

렉시컬 환경 컴포넌트 설정

환경 레코드에 함수 안의 함수와 변수를 기록합니다.
외부 렉시컬 환경 참조에 function 오브젝트의 [[Scope]]설정
함수 안과 밖의 함수와 변수를 사용할 수 있게 됩니다.
실행 콘텍스트(EC):{ 렉시컬 환경 컴포넌트(LEC):{ 환경 레코드(ER):{ point:100 }, 외부 렉시컬 환경 참조(OLER): { title:"책", getTitle: function(){} } } }
JavaScript
복사

외부 렉시컬 환경 참조

스코프와 실행중인 함수가 Context형태이기에
스코프의 변수와 함수를 별도의 처리 없이 즉시 사용 가능.
실행 콘텍스트에서 함수 안과 밖의 함수,변수를 사용할 수 있으므로 함수와 변수를 찾기 위해 실행 콘텍스트를 벗어나지 않아도 됩니다.

변수 환경 컴포넌트

실행 콘텍스트 초기화 단계에서 렉시컬 환경 컴포넌트와 같게 설정합니다.
초기값을 복원할 때 사용하기 위함입니다.
함수 코드가 실행되면 실행 결과를 렉시컬 컴포넌트에 설정합니다. 또한 초기값이 변하게 되기에 이를 유지하기 위한것입니다.
실행 콘텍스트(EC):{ 렉시컬 환경 컴포넌트(LEC):{ }, 변수 환경 컴포넌트(VEC):{ }, this 바인딩 컴포넌트(TBC):{ } }
JavaScript
복사

3. 실행 콘텍스트 실행 과정

1.
getPoint 오브젝트의 [[Scope]]에 글로벌 오브젝트 설정
2.
마지막 줄에서 getPoint()함수 호출
3.
엔진은 실행 콘텍스트 생성 후 안으로 이동
var base = 200; function getPoint(bonus){ var point = 100; return point + base + bonus; }; console.log(getPoint(70));
JavaScript
복사

첫 번째, 준비과정

1.
컴포넌트를 생성하여 실행 콘텍스트에 첨부
렉시컬 환경 컴포넌트
변수 환경 컴포넌트
this바인딩 컴포넌트
2.
환경 레코드를 생성하여 렉시컬 환경 컴포넌트에 첨부합니다.
함수안의 함수, 변수를 바인딩합니다.
3.
외부 렉시컬 환경 참조를 생성하여 렉시컬 환경 컴포넌트에 첨부하고 function 오브젝트의 [[Scope]]를 설정합니다.
2번까지의 진행상황
실행 콘텍스트(EC):{ 렉시컬 환경 컴포넌트(LEC)={ 환경 레코드(ER):{} }, 변수 환경 컴포넌트(VEC): {}, this바인딩 컴포넌트(TBC):{} }
JavaScript
복사
3번까지의 진행상황
실행 콘텍스트(EC):{ 렉시컬 환경 컴포넌트(LEC)={ 환경 레코드(ER):{}, 외부 렉시컬 환경 참조(OLER):{ base: 200 } }, 변수 환경 컴포넌트(VEC): {}, this바인딩 컴포넌트(TBC):{} }
JavaScript
복사

두 번째, 초기화 단계

1.
호출한 함수의 파라미터 값을 호출된 함수의 파라미터 이름에 매핑하고 환경 레코드에 작성합니다.
2.
함수 선언문을 function 오브젝트로 생성합니다.
3.
함수 표현식과 변수에 초기값을 설정합니다.
4.
여기까지는 외부에 실행 상태를 제공하지 않습니다.
실행 콘텍스트(EC):{ 렉시컬 환경 컴포넌트(LEC)={ 환경 레코드(ER):{ bonus: 70, point: undefined }, 외부 렉시컬 환경 참조(OLER):{ base: 200, } }, 변수 환경 컴포넌트(VEC): {}, this바인딩 컴포넌트(TBC):{} }
JavaScript
복사

세 번째, 실행 단계

1.
함수 안의 코드를 실행합니다.
var point = 100;
2.
실행 콘텍스트 안에서 관련된 함수와 변수를 사용할 수 있습니다.
var base = 200; function getPoint(bonus){ var point = 100; return point + base + bonus; }; console.log(getPoint(70));
JavaScript
복사
[실행 결과]
370

예제

아래 코드를 논리적으로 전개해보자.
function book(){ function get(){ return point; }; var point = 123; return get(); }; console.log(book());
JavaScript
복사
1.
book()메소드를 호출하며 실행 컨텍스트 생성 및 안으로 이동합니다.
2.
get 함수와 point를 컨텍스트 안에 환경레코드(ER)에 바인딩합니다.
3.
다시 위로올라가 코드를 실행합니다.
4.
var point= 123 이 실행되여 point는 123이 됩니다.
5.
get()메소드를 만나며 실행 컨텍스트가 생성되고, 그 안으로 이동합니다.
6.
변수 point를 환경레코드에 설정합니다.

4. 환경 레코드, 환경 레코드 구성, 글로벌 환경

환경 레코드 구성

환경 레코드를 구분하는 이유는 기록 대상에 따라 다르기 때문입니다.
선언적 환경 레코드
DER: Declarative Environment Record
function, 변수, catch 문에서 사용합니다.
앞 절에서 환경 레코드에 설정한다고 한 것이 실제로 여기에 설정됩니다.
오브젝트 환경 레코드
OER: Object Environment Record
글로벌 함수와 변수, with문에서 사용
정적이 아니라 동적이기 때문
실행 콘텍스트(EC): { 렉시컬 환경 컴포넌트(LEC): { 환경 레코드(ER): { 선언적 환경 레코드(DER): { point: 123 }, 오브젝트 환경 레코드(OER):{} }, 외부 렉시컬 환경 참조(OLER): {} }, 변수 환경 컴포넌트(VEC): {}, this 바인딩 컴포넌트(TBC): {} }
JavaScript
복사

글로벌 환경

Global Environment
글로벌 오브젝트에서 사용
렉시컬 환경 컴포넌트와 형태가 같습니다.
동적으로 함수와 변수 바인딩
함수에서 var 키워드를 사용하지 않고 변수를 선언하면 글로벌 오브젝트에 설정되기 때문
이런 이유로 오브젝트 환경 레코드 사용
외부 렉시컬 환경 참조 값은 null
실행 콘텍스트(EC): { 글로벌 환경(GE): { 환경 레코드(ER): { 오브젝트 환경 레코드: 글로벌 오브젝트 }, 외부 렉시컬 환경 참조(OLER): null } }
JavaScript
복사

5. this바인딩 컴포넌트

목적

this로, 함수를 호출한 오브젝트의 프로퍼티에 액세스
Ex: this.propertyName

액세스 매커니즘

obj.book()형태에서 this로 obj를 참조할 수 있도록 this 바인딩 컴포넌트에 obj참조를 설정합니다.
obj의 프로퍼티가 변경되면 동적으로 참조를 합니다. 설정이 아닌 참조이기 때문.
내부의 프로퍼티는 동적으로 변경될 수 있는데 this에 이런 프로퍼티를 바인딩하게되면 사용시점에 해당 프로퍼티가 없을 수 있기 때문에 참조할 수 있는 obj객체만 바인딩해주도록 합니다.

this 바인딩 컴포넌트

var obj = {point: 100}; obj.getdPoint = function(){ return this.point; }; obj.getPoint();
JavaScript
복사
1.
마지막 줄에서 obj.getPoint()함수 호출
2.
실행 콘텍스트 생성
3.
3개의 컴포넌트 생성
렉시컬/변수 환경 컴포넌트, this바인딩 컴포넌트
4.
this바인딩 컴포넌트에 getPoint()에서 this로 obj의 프로퍼티를 사용할 수 있게 바인딩
5.
파라미터, 함수 선언문, 변수 선언 없음
6.
return this.point; 실행
7.
this.바인딩 컴포넌트에서 point 검색
getPoint()함수를 호출한 오브젝트가 this 바인딩 컴포넌트에 설정(참조)된 상태
8.
this 바인딩 컴포넌트에 point 프로퍼티가 있기에 100 반환
9.
obj.getPoint()에서 obj의 프로퍼티가 this 바인딩 컴포넌트에 바인딩되도록 의도적으로 설계해야 합니다.
실행 콘텍스트(EC): { 렉시컬 환경 컴포넌트(LEC): { 환경 레코드(ER): { 선언적 환경 레코드(DER): {}, 오브젝트 환경 레코드(OER):{} }, 외부 렉시컬 환경 참조(OLER): {} }, 변수 환경 컴포넌트(VEC): {}, this 바인딩 컴포넌트(TBC): { point: 100, getPoint: function(){} } }
JavaScript
복사

6. 호출 스택(call stack)

call stack
실행 콘텍스트의 논리적 구조
First In Last Out 순서
함수가 호출되면 스택의 가장 위에 실행 콘텍스트가 위치하게 됩니다.
다시 함수안에서 함수를 호출하면 호출된 함수의 실행 콘텍스트가 스택의 가장 위에 놓이게 됩니다.
함수가 종료되면 스택에서 빠져 나옵니다.(FILO순서)
가장 아래는 글로벌 오브젝트 함수가 위치합니다.
function one(){ two(); console.log(1); }; function two(){ three(); console.log(2); }; function three(){ console.log(3); }; one();
JavaScript
복사
[실행 결과]
3
2
1

First In Last Out

call stack에 쌓이는 수행 메소드
차례대로 수행되는 메소드

7. 파라미터 매핑, 함수 호출, 파라미터 값 매핑, 파라미터 이름에 값 매핑 방법

함수 호출

함수가 호출되면 3개의 파라미터 값을 실행 콘텍스트로 넘겨줍니다. 이 때 넘겨주는 값은
함수를 호출한 오브젝트
함수 코드
호출한 함수의 파라미터 값
함수를 호출한 오브젝트를 this바인딩 컴포넌트에서 설정하여 this로 참조합니다.
함수 코드는 function 오브젝트의 [[Code]]에 설정되어 있습니다.
호출한 함수의 파라미터 값은 호출된 함수의 Argument오브젝트에 설정되어 있습니다.

파라미터 값 매핑

파라미터 값 매핑이란?
호출한 함수에서 넘겨 준 파라미터 값을 호출 된 함수의 파라미터 작성 순서에 맞춰 값을 매핑하는 것.
엔진 처리 관점
실행 콘텍스트로 넘겨 준 파라미터 값과 function 오브젝트의 [[FormalParameters]]에 작성된 이름에 값을 매핑하고 결과를 선언적 환경 레코드(DER)에 설정하는 것입니다.
FormalParameters → 호출 된 함수의 파라미터에 작성 된 이름이 있는 곳

파라미터 이름에 값 매핑 방법

1.
여기서 실행 콘텍스트로 넘겨준 파라미터 값을 param이라 지칭합니다.
2.
getTotal 오브젝트의 [[FormalParameters]]에서
호출된 함수의 파라미터 이름을 구합니다.
(설명 편의를 위해 name이라 합니다.)
name은 ["one", "two"]형태입니다.
[[FormalParameters]]는 function 오브젝트를 생성할 때 설정합니다.
3.
name 배열을 하나씩 읽습니다.
4.
param에서 index번째의 값을 구합니다.
인덱스에 값이 없을 경우 undefined 반환
5.
name의 파라미터 이름과 4번에서 구한 값을 선언적 환경 레코드에 설정
{one: 11, two: 22} 형태로 설정합니다.
같은 이름이 있으면 값이 대체됩니다.
6.
name을 전부 읽을 때까지 3번에서 5번까지 반복
var obj = {}; obj.getTotal = function(one, two){ return one + two; } console.log(obj.getTotal(11,22,77));
JavaScript
복사

8. 파라미터 값 할당 기준

파라미터 값 할당 기준에 대해 코드를 분석해가며 알아봅시다.
var obj = {}; obj.getTotal = function(one, two){ var one; console.log(one + two); two = 77; console.log("two:"+two); } obj.getTotal(11, 22);
JavaScript
복사

초기화 단계

1.
obj.getTotal(11, 22) 함수가 호출되면 파라미터 값을 실행 컨텍스트에 넘겨줍니다.
2.
파라미터 이름에 값을 매핑하여 선언적 환경 레코드에 설정합니다. → {one: 11, two: 22}
3.
var one; ⇒ 선언적 환경 레코드에서 one의 존재를 체크 후 파라미터 이름을 설정하였으므로 존재하여 one을 기록하지 않습니다.
4.
two = 77; ⇒선억적 환경 레코드에서 two의 존재를 체크 후 파라미터 일므을 설정하였으므로 존재하며 two를 기록하지 않습니다.
5.
그렇기에 함수에 초기화할 코드가 없습니다(빈 오브젝트나 undefined로 초기화 등록할 코드가 없다는 의미)

실행 단계

1.
선언적 환경 레코드는 {one: 11, two: 22}상태가 됩니다.
2.
var one; ⇒ 단지, 변수 선언이기에 처리하지 않습니다.
3.
console.log(one + two); ⇒ 선언적 환경 레코드에서 one과 two의 값을 구해 연산하여 33을 출력합니다.
4.
two = 77;
⇒ 값을 할당하는 코드이며 실행단계이므로 two에 77을 할당하여 {two: 22}가 {two: 77}로 변경됩니다.
5.
console.log("two:" + two);
⇒ 선언적 환경 레코드에서 two의 값을 구하며 4번 항목에서 설정된 77이 출력됩니다.