아래의 코드 출력 결과를 예상해보자
var callbacks = [];
function print(foo) {
console.log(foo);
}
for (var i = 0; i < 2; i++) {
callbacks.push(() => print(i));
}
for (var callback in callbacks) {
callback();
}
// expected result: ??
선언과 실행이 따로 진행되는 과정 ⇒ 같은 실행컨텍스트 내에서 선언 이전에 실행을 하더라도 실행이 가능한 호이스팅 설명 가능 다만, let const 같은 스코프 단위 선언의 경우에는 불가능
렉시컬 환경에서는 환경 레코드(EnviromentRecord), 외부 렉시컬환경 (outerlexicalEnvironmentReference)으로 나뉘는데 환경 레코드에서는 소스코드의 평가와 실행 내역이 기록되고 외부렉시컬환경에서는 해당 실행컨텍스트 이전 발생한 바깥 스코프의 실행컨텍스트의 렉시컬환경을 참조하여 가지고 있습니다.
외부 렉시컬 환경을 참조 하여 해당 실행 컨텍스트 소스코드 실행 중 사용할 식별자가 환경 레코드에 존재 하지 않는다면 외부 렉시컬 환경을 참조하여 가져와 사용함 ⇒ 클로저 설명 가능
실행 컨텍스트는 스택으로 관리 되는데 우선 전역 실행 컨텍스트가 실행되며 소스코드 평가 과정에서 함수 실행이 있다면 그 함수 실행 컨텍스트가 스택으로 쌓이고 이 컨텍스트가 끝난 뒤 스택에서 빠진 뒤 전역 실행 컨텍스트로 진행되는 스택의 형식을 가지고 있습니다.
if 문의 경우에도 각각의 스코프에 해당하는 실행 컨텍스트를 가지고 있으며 실행컨텍스트의 외부 렉시컬 환경에는 if문 이전에 해당하는 함수 혹은 전역의 실행 컨텍스트를 참조하고 있습니다.
또한 let과 const와 같이 블록 범위 선언의 경우에는 환경 레코드에 저장되는 방식이 다르게 되어 선언 이전에 실행 시 에러를 일으키어 호이스팅을 막는 특성을 가지고 있습니다.
let: not defined
const: not initialized