실행 콘텍스트
function music(title){
var musicTitle = title;
};
music("음악");
- Exeuction Context
- 함수가 실행되는 영역, 묶음
- 함수 코드를 실행하고 실행 결과를 저장
- 스펙상의 사양
- music("음악")으로 함수를 호출하면
- 엔진은 실행 콘텍스트를 생성하고
- 실행 콘텍스트 안으로 이동
- 실행 콘텍스트 실행 단계
- 준비 단계
- 초기화 단계
- 코드 실행 단계
- Execution Context 생성 시점
- 실행 가능한 코드를 만났을 때
- 실행 가능한 코드 유형
- 함수 코드
- 글로벌 코드
- eval 코드
- 코드 유형을 본리한 이유
- 실행 콘텍스트에서 처리 방법과 실행 환경이 다르기 때문
- 함수 코드: 렉시컬 환경
- 글로벌 코드: 글로벌 환경
- eval 코드: 동적 환경
실행 콘텍스트 상태 컴포넌트
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC): { },
변수 환경 컴포넌트(VEC): { },
this 바인딩 컴포넌트(TBC): { },
}
- 실행 콘텍스트 상태를 위한 오브젝트
- 실행 콘텍스트 안에 생성
- 상태 컴포넌트 유형
- 렉시컬 환경 컴포넌트(LEC): Lexical Environment Component
- 변수 환경 컴포넌트(VEC): Variable Environment Component
- this 바인딩 컴포넌트(TBC): This Binding Component
1. 렉시컬 환경 컴포넌트
- 함수와 변수의 식별자 해결을 위한 환경 설정
- 함수 초기화 단계에서 해석한
- 함수와 변수를 {name: value} 형태로 저장
- 이름으로 함수와 변수를 검색할 수 있게 됨
- 함수 밖의 함수와 변수 참조 환경 설정
- 함수 밖의 함수와 변수를 사용할 수 있게 됨
렉시컬 환경 컴포넌트 구성
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC): {
환경 레코드(ER): {
point: 100
},
외부 렉시컬 환경 참조(OLER): {
title: "책",
getTitle: function(){}
}
}
}
- 렉시컬 환경 컴포넌트 생성
- function, with, try-catch에서 생성
- 컴포넌트 구성
- 환경 레코드(ER): Environment Record
- 외부 렉시컬 환경 참조(OLER): Outer Lexical Environment Reference
렉시컬 환경 컴포넌트 설정
- 환경 레코드에 함수 안의 함수와 변수를 기록
- 외부 렉시컬 환경 참조에 function 오브젝트의 [[Scope]]를 설정
- 따라서 함수 안과 밖의 함수와 변수를 사용할 수 있게 됨
환경 레코드 구성
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC) = {
환경 레코드(ER): {
선언적 환경 레코드(DER): {
point: 123
},
오브젝트 환경 레코드(OER): {}
},
외부 렉시컬 환경 참조(OLEC): {}
},
변수 환경 컴포넌트(VEC): {},
this 바인딩 컴포넌트(TBC): {}
}
- 환경 레코드를 구분하는 이유
- 기록 대상에 따라 다르기 때문
- 선언적 환경 레코드
- DER: Declarative Environment Record
- function, 변수, catch 문에서 사용
- 앞 절에서 환경 레코드에 설정한다고 했는데 설명을 위한 것으로 실제로 여기에 설정
- 오브젝트 환경 레코드
- OER: Object Environment Record
- 글로벌 함수와 변수, with 문에서 사용
- 정적이 아니라 동적이기 때문
글로벌 환경
실행 콘텍스트(EC): {
글로벌 환경(GE): {
환경 레코드(ER): {
오브젝트 환경 레코드: 글로벌 오브젝트
},
외부 렉시컬 환경 참조(OLER): null
}
}
- Global Environment
- 글로벌 오브젝트에서 사용
- 렉시컬 환경 컴포넌트와 형태 같음
- 동적으로 함수와 변수 바인딩
- 함수에서 var 키워드를 사용하지 않고 변수를 선언하면 글로벌 오브젝트에 설정되기 때문
➡ 이런 이유로 오브젝트 환경 레코드 사용
- 함수에서 var 키워드를 사용하지 않고 변수를 선언하면 글로벌 오브젝트에 설정되기 때문
- 외부 렉시컬 환경 참조 값은 null
외부 렉시컬 환경 참조
- 스코프와 실행중인 함수가 Context 형태이므로
- 스코프의 변수와 함수를 별도의 처리 없이 즉시 사용할 수 있음
- 실행 콘텍스트에서
- 함수 안과 밖의 함수, 변수를 사용할 수 있으므로
- 함수와 변수를 찾기 위해 실행 콘텍스트를 벗어 나지 않아도 됨
2. 변수 환경 컴포넌트
- 실행 콘텍스트 초기화 단계에서
- 렉시컬 환경 컴포넌트와 같게 설정
- 이렇게 하는 이유는?
- 초기값을 복원할 때 사용하기 위한 것
- 함수 코드가 실행되면
- 실행 결과를 렉시컬 환경 컴포넌트에 설정
- 초기값이 변하게 되므로 이를 유지하기 위한 것
3. this 바인딩 컴포넌트
- 목적
- this로, 함수를 호출한 오브젝트의 프로퍼티에 악세스
- 예: this.propertyName
- 악세스 메커니즘
- obj.book() 형태에서
- this로 obj를 참조할 수 있도록
- this 바인딩 컴포넌트에 obj 참조를 설정
- obj의 프로퍼티가 변경되면 동적으로 참조
- 설정이 아닌 참조이기 때문
var obj = {point: 100};
obj.getPoint = function(){
return this.point;
};
obj.getPoint();
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC) = {
환경 레코드(ER): {
선언적 환경 레코드(DER): {},
오브젝트 환경 레코드(OER): {}
},
외부 렉시컬 환경 참조(OLEC): {}
},
변수 환경 컴포넌트(VEC): {},
this 바인딩 컴포넌트(TBC): {
point: 100,
getPoint: function(){}
}
}
getPoint() 함수에서 100이 반환되는 과정
준비 단계
- 마지막 줄에서 obj.getPont() 함수 호출
- 실행 콘텍스트 생성
- 3개의 컴포넌트 생성
- 렉시컬/변수 환경 컴포넌트, this 바인딩 컴포넌트
- this 바인딩 컴포넌트에
- getPoint()에서 this로 obj의 프로퍼티를 사용할 수 있도록 바인딩
초기화 단계
- 파라미터, 함수 선언문, 변수 선언 없음
실행 단계
- return this.point; 실행
- this 바인딩 컴포넌트에서 point 검색
- getPoint() 함수를 호출한 오브젝트가
- this 바인딩 컴포넌트에서 설정(참조)된 상태
- this 바인딩 컴포넌트에
- point 프로퍼티가 있으므로 100을 반환
추가 설명
- obj.getPoint()에서 obj의 프로퍼티가
- this 바인딩 컴포넌트에 바인딩되도록 의도적으로 설계해야 함
실행 콘텍스트 실행 과정
var base = 200;
function getPoint(bonus){
var point = 100;
return point + base + bonus;
};
log(getPoint(70));
// 370
- getPoint 오브젝트의 [[Scope]]에 글로벌 오브젝트 설정
- 마지막 줄에서 getPoint() 함수 호출하면
- 엔진은 실행 콘텍스를 생성하고 실행 콘텍스트 안으로 이동
준비 단계
- 컴포넌트를 생성하여 실행 콘텍스트에 첨부
- 렉시컬 환경 컴포넌트
- 변수 환경 컴포넌트
- this 바인딩 컴포넌트
- 환경 레코드를 생성하여 렉시컬 환경 컴포넌트에 첨부
- 함수 안의 함수, 변수를 바인딩
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC) = {
환경 레코드(ER): {}
},
변수 환경 컴포넌트(VEC): {},
this 바인딩 컴포넌트(TBC): {}
}
- 외부 렉시컬 환경 참조를 생성하여 렉시컬 환경 컴포넌트에 첨부하고
- function 오브젝트의 [[Scope]]를 설정
<여기까지의 모습>
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC) = {
환경 레코드(ER): {},
외부 렉시컬 환경 참조(OLEC): {
base: 200
}
},
변수 환경 컴포넌트(VEC): {},
this 바인딩 컴포넌트(TBC): {}
}
초기화 단계
- 호출한 함수의 파라미터 값을
- 호출된 함수의 파라미터 이름에 매핑
- 환경 레코드에 작성
- 함수 선언문을 function 오브젝트로 생성
- 함수 표현식과 변수에 초기값 설정
- 여기까지는 외부에 실행 상태를 제공하지 않음
<여기까지 모습>
실행 콘텍스트(EC): {
렉시컬 환경 컴포넌트(LEC) = {
환경 레코드(ER): {
bonus: 70,
point: undefined
},
외부 렉시컬 환경 참조(OLEC): {
base: 200
}
},
변수 환경 컴포넌트(VEC): {},
this 바인딩 컴포넌트(TBC): {}
}
실행 단계
- 함수 안의 코드를 실행
- 실행 콘텍스트 안에서 관련된 함수와 변수를 사용할 수 있음
호출 스택(call stack)
- call stack
- 실행 콘텍스트의 논리적 구조
- First in Last Out 순서
- 함수가 호출되면 스택의 가장 위에 실행 콘텍스트가 위치하게 됨
- 다시 함수 안에서 함수를 호출하면 호출된 함수의 실행 콘텍스트가 스택의 가장 위에 놓이게 됨
- 함수가 종료되면 스택에서 빠져 나옴(FILO 순서)
- 가장 아래는 글로벌 오브젝트의 함수가 위치
function one(){
two();
log(1);
};
function two(){
three();
log(2);
};
function three(){
log(3);
};
one();
// 3
// 2
// 1
- 함수가 호출되면 3개의 파라미터 값을 실행 콘텍스트로 넘겨 줌
- 함수를 호출한 오브젝트
- 함수 코드
- 호출한 함수의 파라미터 값
- 함수를 호출한 오브젝트를
- this 바인딩 컴포넌트에 설정하여 this로 참조
- 함수 코드
- function 오브젝트의 [[Code]]에 설정되어 있음
- 호출한 함수의 파라미터 값
- 호출된 함수의 Argument 오브젝트에 설정
파라미터 값 매핑
- 파라미터 값 매핑이란?
- 호출한 함수에서 넘겨 준 파라미터 값을
- 호출된 함수의 파라미터 작성 순서에 맞추어 값을 매핑하는 것
- 엔진 처리 관점
- 실행 콘텍스트로 넘겨 준 파라미터 값과
- function 오브젝트의 [[FormalParameters]]에 작성된 이름에 값을 매핑하고
- 결과를 선언적 환경 레코드에 설정하는 것
파라미터 이름에 값 매핑 방법
var obj = {};
obj.getTotal = function(one, two){
return one + two;
}
log(obj.getTotal(11, 22, 77));
// 33
- 실행 콘텍스트로 넘겨준 파라미터 값을 param이라고 하자
- getTotal 오브젝트의 [[FormalParameters]]에서
- 호출된 함수의 파라미터 이름을 구함 ➡ name이라고 가정
- name은 ["one", "two"] 형태
- [[FormalParameters]]는 function 오브젝트를 생성할 때 설정
- name 배열을 하나씩 읽음
- param에서 index번째의 값을 구함
- 인덱스에 값이 없으면 undefined 반환
- name의 파라미터 이름과 4번에서 구한 값을
- 선언적 환경 레코드에 {one: 11, two: 22} 형태로 설정
- 같은 이름이 있으면 값이 대체됨
- name을 전부 읽을 때까지 3번에서 5번까지 반복
파라미터 값 할당 기준
var obj = {};
obj.getTotal = function(one, two){
var one;
log(one + two);
two = 77;
log("two:" + two);
}
obj.getTotal(11, 22);
// 33
// two:77
아래의 설명을 따라가면서 {key: value} 형태로 만들기
초기화 단계
- obj.getTotal(11, 22) 함수가 호출되면
- 파라미터 값을 실행 콘텍스트로 넘겨줌
- 파라미터 이름에 값을 매핑하여
- 선언적 환경 레코드에 설정
- {one: 11, two: 22}
- var one;
- 선언적 환경 레코드에서 one의 존재를 체크
- 파라미터 이름을 설정하였으므로 존재하며 one을 기록하지 않음
- two = 77;
- 선언적 환경 레코드에서 two의 존재를 체크
- 파라미터 이름을 설정하였으므로 존재하며 two를 기록하지 않음
- 함수에 초기화할 코드가 없음
- 첫 번째 줄로 이동하여 함수 코드를 실행
실행 단계
- 선언적 환경 레코드는 {one: 11, two: 22} 상태
- var one;
- 단지 변수 선언이므로 처리하지 않음
- console.log(one + two);
- 선언적 환경 레코드에서 one과 two 값을 구함
- 11 + 22의 결과인 33이 [실행 결과]에 출력
- two = 77;
- 값을 할당하는 코드이며 실행 단계이므로
- 선언적 환경 레코드의 two에 77을 할당하며
- {two: 22}가 {two: 77}로 변경됨
- console.log("two:" + two);
- 선언적 환경 레코드에서 two 값을 구함
- [실행 결과]에 two:77이 출력됨
정리 시간
var obj = {};
obj.getTotal = function(one, two, two){
log(one + two);
}
obj.getTotal(11, 22, 55);
// 66
- 위의 코드를 기준으로 엔진 관점에서 [실행 결과]에 출력된 값의 논리를 제시하세요.
- 함수의 파라미터 값이 매핑되는 과정을 {key: value} 형태로 기술하고
- 값이 출력되는 논리를 기술하세요.
- 힌트
- 두 번째, 세 번째 파라미터 이름이 같음
'Javascript > [인프런] 자바스크립트 중고급' 카테고리의 다른 글
[자바스크립트 중고급] 6. this (0) | 2022.02.18 |
---|---|
[자바스크립트 중고급] 5. function instance (0) | 2022.02.18 |
[자바스크립트 중고급] 3. 스코프(Scope) (0) | 2022.02.17 |
[자바스크립트 중고급] 2. Argument (0) | 2022.02.17 |
[자바스크립트 중고급] 1.Function 오브젝트 (0) | 2022.02.17 |