💡 자바스크립트 엔진은 실행 가능한 코드를 만나면 그 코드를 평가해서 실행 문맥으로 만듭니다.
"실행 가능한 코드가 실제로 실행되고 관리되는 영역"
실행에 필요한 모든 정보를 여러 컴포넌트가 나누어 관리합니다.
// 실행문맥
ExecutionContext = {
// 렉시컬 환경 컴포넌트
LexicalEnvironment: {},
// 변수 환경 컴포넌트
VariableEnvironment: {},
// 디스 바인딩 컴포넌트
ThisBinding: null
}
"자바스크립트 엔진이 자바스크립트 코드를 실행하기 위해 함수, 블록의 유효범위 안의 식별자와 그 결괏괎이 저장되는 공간"
// 렉시컬 환경 컴포넌트
LexicalEnvironment: {
// 환경 레코드
EnviromentRecord: {},
// 외부 렉시컬 환경 참조
OuterLexicalEnvironment Refoerence: {}
}
"렉시컬 환경 안의 식별자와 그 식별자가 가리키는 값의 묶음이 실제로 저장되는 영역"
변수 객체와 유사한 역할
// 환경 레코드
EnvironmentRecord: {
// 선언적 환경 레코드
DeclarativeEnvironmentRecord: {},
// 객체 환경 레코드
ObjectEnvironmentRecord: {}
}
저장하는 값의 유형에 따라 쓰임새가 달라집니다.
"함수를 둘러싸고 있는 코드가 속한 렉시컬 환경 컴포넌트의 참조가 저장"
중첩된 함수 안에서 바깥 코드에 정의된 변수를 읽거나 써야할 때, 자바스크립트 엔진은 외부 렉시컬 환경 참조를 따라 한 단계씩 렉시컬 환경을 거슬러 올라가서 그 변수를 검색합니다.
자바스크립트 인터프린터는 시작하자마자 렉시컬 환경 타입의 "전역 환경"을 생성합니다.
1. 자바스크립트 인터프린터는 웹 페이지를 읽어 들인 후에 전역 환경을 생성합니다.
2. 전역 객체를 생성한 다음 전역 환경 레코드에 전역 객체의 참조를 대입합니다.
3. 최상위 레벨(함수 바깥에 있는 코드)의 this는 전역 객체를 가리킵니다.
this === window // true
// 전역 환경
GlobalEnvironment = {
ObjectEnvironmentRecord: {
bindObject: window
},
OuterLexicalEnvironmentReference: null
}
// 전역 실행 문맥
ExcutionContext = {
LexicalEnvironment: GlobalEnvironment,
ThisBinding: window
}
전역 환경과 전역 객체를 생성한 후에는 자바스크립트 프로그램을 읽어 들입니다. 다 읽어드린 후에는 프로그램을 평가하고, 최상위 레벨에 var 문으로 작성한 전역 변수는 전역 환경의 환경 레코드의 프로퍼티로 추가됩니다.
// 전역 환경
GlobalEnvironment = {
// 전역 환경의 환경 레코드인 객체 환경 레코드에 Window의 참조가 설정되어 있다.
ObjectEnvironmentRecord: {
bindObject: window
},
OuterLexicalEnvironmentReference: null
}
이처럼 최상위 레벨에서 선언된 변수와 함수는 프로그램을 평가할 때 객체 환경 레코드에 기록됩니다.
따라서 최상위 레벨에 선언된 함수와 변수는 프로그램을 평가하는 단계에서 이미 객체 환경 레코드에 추가된 상태이기 때문에 코드의 어느 위치에 작성해도 전체 프로그램을 참조할 수 있습니다. "끌어올림"
프로그램은 실행 문맥 안에서 실행됩니다. 실행 문맥은 실행 가능한 코드별로 생성됩니다.
실행 문맥은 "스택" 이라는 구조로 관리됩니다.
1. 가장 먼저 실행하는 코드는 전역 코드이기 때문에 이 대문에 스택의 맨 아랫부분에는 항상 전역 코드를 실행하기 위한 실행 문맥이 있습니다.
2. 전역코드 안에서 함수를 실행하면 그 함수를 실행하기 위한 실행 문맥을 스택에 push합니다.
3. 그리고 그 함수의 작업을 끝내고 함수를 호출한 부분에 제어권이 들어오면 스택에서 pop합니다.
➡️ 중첩함수의 경우 새로운 실행문맥을 만들어서 스택에 push합니다.
➡️ 함수에 있는 코드를 실행하는 도중 다른 함수를 호출하면 그 함수의 실행 문맥도 스택에 push합니다. (재귀 호출의 경우도 적용)