자바스크립트 엔진은 Executable code를 만나면 코드를 평가해 실행 문맥으로 만든다.
실행 가능한 코드는 다음과 같다.
실행 문맥은 실행 가능한 코드가 실제로 실행되고 관리되는 영역으로 실행에 필요한 정보를 컴포넌트 여러개가
나누어 관리하고 있다.
실행 문맥의 구조를 자바스크립트 객체처럼 표현을 하자면 아래와 같다.
여기서 렉시컬 환경 컴포넌트와 변수 환경 컴포넌트는 동일한 것으로 취급하고 정리하겠다.
실행 문맥 = {
'렉시컬 환경 컴포넌트' : {},
'변수 환경 컴포넌트' : {},
'디스 바인딩 컴포넌트' : null
}
실행 문맥의 구성 요소인 렉시컬 환경 컴포넌트는 자바스크립트 엔진이 자바스크립트 코드를 실행하기 위해 자원을 모아 둔 곳으로 구체적으로 함수 또는 블록의 유효 범위안에 있는 식별자와 그 값을 키와 값의 쌍으로 묶어 저장하는 곳이다.
렉시컬 환경 컴포넌트 : {
'환경 레코드' : {},
'외부 렉시컬 환경 참조' : {},
}
유효 범위 안에 있는 식별자를 기록하고 실행하는 공간 식별자와 결괏값을 바인드해서 저장한다.
환경 레코드는 선언적 환경 레코드와 객체 환경 레코드로 구성되어 있다.
환경 레코드 : {
'선언적 환경 레코드' : {},
'객체 환경 레코드' : {},
}
함수 안에 함수가 있는 경우를 생각해보자 내부 함수 기준에서는 유효 범위 너머에 또 다른 유효 범위가 있다.
외부 렉시컬 환경 참조에는 함수를 둘러싸고 있는 코드가 속한 렉시컬 환경 컴포넌트의 참조가 저장된다.
즉, 내부 함수에서 외부 함수의 유효 범위에 있는 식별자와 값을 참조할 수 있게 해준다.
자바스크립트 인터프리터는 시작하자마자 렉시컬 환경 타입의 전역 환경을 만든다.
그리고 전역 객체를 생성한 다음 전역 환경의 객체 환경 레코드에 전역 객체의 참조를 대입한다.
의사 코드를 만들어보면 다음과 같다.
전역환경 = {
'객체 환경 레코드' : {
bindObject: window
},
'외부 렉시컬 환경 참조' : null
}
실행 문맥 = {
'렉시컬 환경' : 전역 환경,
'ThisBinding' : window
}
웹 브라우저 실행 환경에서는 window 객체가 전역 객체이므로 객체 환경 레코드에는 window의 참조가 할당된다.
따라서 전역 환경의 변수와 함수를 window 객체 안에서 검색하게 된다.
전역 환경은 최상단 환경이기 때문에 외부에 다른 렉시컬 환경이 없다. 따라서 외부 렉시컬 환경 참조는 없다.
thisbinding 컴포넌트에도 window 객체의 참조가 할당되어 this가 window를 가리킨다.
자바스크립트 엔진은 전역 코드를 평가할 때 최상위 레벨에 var 키워드로 선언된 변수를 전역 환경의 환경레코드에 프로퍼티로 추가한다. 여기서 키는 식별자이고 value는 undefined로 저장이 된다.
최상위 레벨에 선언된 변수와 함수는 프로그램을 평가하는 시점에 환경 레코드에 추가된다.
위와 같은 방식으로 인해 함수와 변수의 선언이 끌어올려지는 호이스팅이 발생한다.