2019. 3. 31. 18:17ㆍWeb Programming/_JAVA SCRIPTS
실행 가능한 코드
자바스크립트 엔진은 실행가능한 코드를 만나면 그 코드를 평가해서 실행문맥(ExecutionContext)으로 만든다.
실행 가능한 코드의 유형은 다음과 같다.
- 전역코드 : 전역객체 window아래에 정의된 함수를 말함.
- 함수코드 : 문자 그대로 함수를 말함.
- eval코드 : eval함수를 말함.
자바스크립트 엔진이 실행가능한 코드의 유형을 분류하는 이유는
실행문맥을 초기화하는 환경과 과정이 다르기 때문이다.
실행문맥의 구성
실행문맥(Execution Context)은 실행 가능한 코드가 실제로 실행되고 관리되는 영역
실행에 필요한 모든 정보를 컴포넌트 여러개가 나누어 관리 (렉시컬환경컴포넌트, 변수환경 컴포넌트,
디스바인딩 컴포넌트)
//실행 문맥
ExecutionContext = {
//렉시컬 환경 컴포넌트
LexicalEnvironment : { },
//변수 환경 컴포넌트
VariableEnvironment : { },
//디스 바인딩 컴포넌트
ThisBinding : null,
}
-렉시컬 환경 컴포넌트와 변수환경 컴포넌트는 앞으로 설명할 렉시컬환경타입의 컴포넌트 이다.
렉시컬 환경 컴포넌트와 변수환경 컴포넌트는 타입이 같고, 실제로 내부 값이 같으므로 똑같이 취급해도
무리가 없다.
-디스바인딩 컴포넌트는 그 함수를 호출한 객체의 참조가 저장되는 곳.
렉시컬 환경 컴포넌트는 새로운 실행 문맥이 생길때마다 같이 생성되는 컴포넌트이다.
<script>
var i;
function test() {
var x;
var y;
function inner() {
}
}
</script>
위 코드의 경우
전역실행문맥과, test()라는 함수의 자료가 저장되는 실행문맥, test()함수 내부의 inner() 함수에 자료가 저장되는 실행문맥해서 3개의 ExcutionContext가 생성이 된다.
그리고 코드가 실행될때 호출스택에 의해 실행 문맥 단위로 호출이 된다.
렉시컬 환경 컴포넌트의 구조
//실행 문맥
ExecutionContext = {
---------------------------------------------------------------
//렉시컬 환경 컴포넌트
LexicalEnvironment : {
EnvironmentRecord : { },
OuterLexicalEnvironment Reference : { }
},
---------------------------------------------------------------
//변수 환경 컴포넌트
VariableEnvironment : { },
//디스 바인딩 컴포넌트
ThisBinding : null,
}
구분을 위해 구분선을 넣어보았다. 렉시컬 컴포넌트는 위와같이 환경레코드(EnvironmentRecord)와 외부 렉시컬 환경 참조(OuterLexicalEnvironment Reference)로 구성되어 있다.
환경레코드는 유효범위( {}로 묶여있는 범위 } 안에 포함된 식별자를 기록하고, 실행하는 영역
자바스크립트엔진은 유효범위 안의 식별자와 결괏값을 바인드해, 환경 레코드에 기록한다.
외부 렉시컬 환경 참조 중첩되어있는 함수에서 유효범위 너머의 유효범위도 검색할수 있어야 한다.
현제 유효범위를 감싸고있는 코드에 속한 렉시컬환경 컴포넌트의 참조가 저장되어, 바깥 코드의 데이터에 접근을 가능하게 해준다. 이 외부렉시컬환경참조를 따라 한단계씩 렉시컬환경을 거슬러 올라가서 변수를 검색한다.
환경 레코드의 구성
//실행 문맥
ExecutionContext = {
//렉시컬 환경 컴포넌트
LexicalEnvironment : {
---------------------------------------------------------------
//환경 레코드
EnvironmentRecord : {
//선언적 환경 레코드
DeclarativeEnvironmentRecord : { },
//객체 환경 레코드
ObjectEnvironmentRecord : { }
},
---------------------------------------------------------------
//외부 렉시컬 환경 참조
OuterLexicalEnvironment Reference : { }
},
//변수 환경 컴포넌트
VariableEnvironment : { },
//디스 바인딩 컴포넌트
ThisBinding : null,
}
선언적 환경 레코드는 실제로 함수와 변수, catch문의 식별자와 실행 결과가 저장되는 영역이다.
객체환경 레코드는 실행문맥 외부에 별도로 저장된 객체의 참조에서 데이터를 읽거나 쓴다.
즉, with문의 렉시컬 환경이나 전역객체처럼 별도의 객체에 저장된 데이터는 그 객체가 가진 키와 값의 쌍을 복사해 오는것이 아니라 그 객체의 참조를 가져와서 객체 환경 레코드의 bindObject라는 프로퍼티에 바인드하도록 되어있다.
결론적으로 일반적인 실행문맥(ExecutionContext)는 다음과같은 구조로 이루어 진다.
//실행 문맥
ExecutionContext = {
//렉시컬 환경 컴포넌트
LexicalEnvironment : {
//환경 레코드
EnvironmentRecord : {
//선언적 환경 레코드
DeclarativeEnvironmentRecord : { },
//객체 환경 레코드
ObjectEnvironmentRecord : { }
},
//외부 렉시컬 환경 참조
OuterLexicalEnvironment Reference : { }
},
//변수 환경 컴포넌트
VariableEnvironment : { },
//디스 바인딩 컴포넌트
ThisBinding : null,
}
하지만, 전역실행문맥의 구조는 위의 구조와 조금의 차이가 있다.
자바스크립트 인터프리터는 코드가 시작하자마자 렉시컬환경 타입의 전역 환경을 생성한다.
조금 아래쪽에 위 코드와 비교하는 코드를 작성해보겠다. 먼저 전역환경의 구조부터 익혀야 한다.
//전역 환경
GlobalEnvironment = {
ObjectEnvironmentRecord : {
bindObject : window
},
OuterLexicalEnvironmentReference : null
}
위의 구조로 이루어진 전역환경은 렉시컬환경 타입으로,
LexicalEnvironment : GlobalEnvironment, 와 같은 구조가 되어진다.
//전역실행 문맥
ExecutionContext = {
//렉시컬 환경 컴포넌트
LexicalEnvironment : {
--------전역환경(GlobalEnvironment)----------
ObejctEnvironmentRecord : {
bindObject : window
},
OuterLexicalEnvironment Reference : null
---------------------------------------------
},
//디스 바인딩 컴포넌트
ThisBinding : window,
}
웹 브라우저의 자바스크립트 실행 환경에서는 Window 객체가 전역 객체이므로 객체 환경 레코드의 bindObject 프로퍼티에는 전역객체 Window의 참조가 할당된다. 또한 전역환경의 외부에는 다른 렉시컬 환경이 없으므로 외부렉시컬 참조에는 null이 할당된다.
그리고 전역실행문맥의 디스바인딩 컴포넌트에도 Window의 참조가 할당되어 전역 실행 문맥의 this는 Window를 가리키게 되고, 전역 실행 문맥의 프로퍼티를 디스바인딩 컴포넌트 안에서 검색하게 된다.
정리해 보면,
<script>
var globalVar1;
var globalVar2 = 123;
var globarVar3 = { x : 'x', y : 'y'};
function localFunction() {
var localVar1;
var localVar2 = 123;
function innerFunction() {
var innerVar1;
var innerVar2;
}
}
</script>
위와 같은 코드가 있을 경우 먼저 코드가 실행되기전 평가 단계에서 전역실행문맥이 아래와 같이 생성 될것이다.
(전역으로 선언된 변수와, 함수의 경우 전역환경의 환경레코드(객체 환경 레코드)에 프로퍼티로 기록하게 된다)
//전역실행 문맥
ExecutionContext = {
//렉시컬 환경 컴포넌트
LexicalEnvironment : {
ObejctEnvironmentRecord : {
bindObject : window,
globalVar1 : undefined,
globalVar2 : 123,
globalVar3 : { x : 'x', y : 'y' }
localFunction : 해당 중첩함수의 참조값
},
OuterLexicalEnvironment Reference : null
},
//디스 바인딩 컴포넌트
ThisBinding : window,
}
//localFunction() 실행 문맥
ExecutionContext = {
LexicalEnvironment : {
EnvironmentRecord : {
DeclarativeEnvironmentRecord : {
localVar1 = undefined,
localVar2 = 123,
innerFunction = 해당 중첩함수의 참조값
},
ObjectEnvironmentRecord : {
bindObject : window
// 전역 객체의 참조만을 가져온다.
}
},
OuterLexicalEnvironment Reference : window
// 외부 렉시컬 환경의 참조만 가져온다.
// 외부 렉시컬 환경의 데이터들은 가져온 참조를 통해 접근.
},
ThisBinding : 현재 함수를 호출한 함수의 참조
}
innerFunction()의 렉시컬환경 참조는 위와같이 생성되어, 실행된다.
호출 스택에서 실행문맥을 호출하는 방식이다.
실제로 실행문맥은 실행이 될때 생성되어 호출된다.
'Web Programming > _JAVA SCRIPTS' 카테고리의 다른 글
셰익스피어의 피보나치수열 (0) | 2018.09.12 |
---|---|
헤밍웨이의 피보나치수열 (0) | 2018.09.12 |