실행할 코드에 제공할 환경 정보들을 모아놓은 객체. 자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 1. 선언된 변수를 위로 끌어올리고(hoisting) 2. 외부 환경 정보를 구성하고 3. this 값을 설정한다.
var a = 1;
function outer() {
function inner() { tdz
console.log(a); // undefined
var a = 3;
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
코드 실행 -> 전역(in) -> 전역(중단) -> outer(in) -> outer(중단) -> inner(in) -> inner(out) + outer(재개) -> outer(out) + 전역(재개) -> 전역(out) -> 종료
실행 컨텍스트에 담기는 정보
(1) VariableEnvironment: 현재 컨텍스트 내의 식별자 정보(record), 외부 환경 정보, 선언 시점 LexicalEnvironment의 snapshot
(2) LexicalEnvironment: VE와 동일하나, 변경사항을 실시간으로 반영
(3) ThisBinding: this가 function 안에서 어떤 기능을 할 지 결정해주는 역할 (this 식별자가 바라봐야 할 객체)
Record
현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장(기록)
함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등
컨텍스트 내부를 순서대로 훑어가며 수집
hoisting
변수정보 수집을 모두 마쳤으나 실행 컨텍스트가 관여할 코드는 실행 전의 상태
var a = 1;
function outer() {
function inner() {
console.log(a); // undefined
var a = 3;
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
위의 코드에서 첫번째 console.log(a);가 왜 1이 아니라 undefined를 반환하는지 어제부터 고민하느라 머리카락 다 쥐어뜯었는데, 아마도 내가 이해한 바에 따르면,
/** 호이스팅 적용(아마도 이렇게 될 것) **/
var a = 1;
function outer() {
function inner() {
var a;
console.log(a); // 바로 이부분!!
a = 3;
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
이 코드의 실행컨텍스트를 수집할 때, 호이스팅에 의해서 변수 식별자와 함수가 위로 끌어올려짐에 따라 var a;는 선언만 되고 값이 할당되기 전이므로 첫번째 console.log(a)는 undefined가 찍히는 것이다.
// 함수 선언문을 사용하면 함수 전체가 hoisting된다.
function sum (a, b) {
return a + b;
}
var multiply = function (a, b) {
return a + b;
}
// 같은 내용이라도 함수 표현식을 사용하면
// hoisting의 양상이 달라진다.
/** 호이스팅 적용 **/
var multiply;
multiply = function (a, b) {
return a + b;
}
함수 선언문과 표현식의 hoisting 차이 때문에 협업을 많이 하고 복잡한 코드일수록, 전역 공간에서 이루어지는 코드 협업일수록 함수 표현식을 활용하는 것이 좋겠다.
식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해 나가는 것
예를 들어 A함수 내부에 B함수가 있다면, A함수가 선언될 때에는 전역함수의 LE를, B함수가 선언될 때는 A함수의 LE를 outer로 갖는다.
각각의 실행 컨텍스트는 LE 안에 record와 outer를 가지고 있고, outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE 정보가 다 들어있으니 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있다.