동일한 환경
에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고, 이를 콜 스택에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장
var a = 1;
function outer(){
function inner(){
console.log(a);
var a = 3;
}
inner();
console.log(a);
}
outer();
console.log(a);
VariableEnvironment
현재 컨텍스트 내의 식별자들에 대한 정보
(EnvironmentRecord)
외부환경 정보(OuterEnvironmentReference)
LexicalEnvironment: 처음에는 VariableEnvironment와 같지만 변경사항이 실시간 반영됨
EnvironmentRecord에는 현재 컨텍스트와 관련된 코드의 식별자 정보(매개변수, 선언한 함수)들이 저장됨
컨텍스트 내부 전체를 처음부터 끝가지 쭉 훑어나가며 순서대로 수집.
코드 실행 전에 자바스크립트 엔진은 이미 해당 환경에 속한 코드의 변수명을 모두 알고 있는 셈
따라서 '자바스크립트 엔진은 식별자들을 최상단으로 끌어올려놓은 다음 실제 코드를 실행한다' 라고 생각해도 괜찮음. => 호이스팅
문제)
function a () {
var x = 1;
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x)
}
a();
정답보기
function a () {
var x;
var x;
var x;
x = 1;
console.log(x); // 1
console.log(x); // 1
x = 2;
console.log(x) // 2
}
해설) environmentRecord는 현재 실행될 컨텍스트의 대상 코드 내에 어떤 식별자들이 있는지에만 관심이 있고, 각 식별자에 어떤 값이 할당될 것인지는 관심이 없음. 따라서 변수를 호이스팅할때 변수명만 끌어올리고 할당 과정은 원래 자리에 그대로 둠.
함수를 정의하는 방식 세 가지
// 함수 선언문
function a(){ /* ... */ }
a();
// 익명함수 표현식
var b = function (){ /* ... */ }
b();
// 기명 함수 표현식
var c = function d(){ /* ... */ }
c();
d(); // 에러
문제)
console.log(sum(1, 2));
console.log(multiply(3,4));
function sum (a, b) {
return a + b;
}
var multiply = function (a, b) {
return a * b;
}
정답보기
var sum = function (a, b) { // 함수선언문 전체를 끌어올림
return a + b;
}
var multiply;
console.log(sum(1, 2)); // 3
console.log(multiply(3,4)); // multiply is not a function
multiply = function (a, b){
return a * b;
}
해설) 함수 선언문은 전체가 끌어올려지는 이유는 자바스크립트의 창시자 브랜든 아이크가 자바스크립트를 유연하고 배우기 쉬운 언어로 만들고자 했기 때문, 덕분에 함수를 선언한 위치와 무관하게 그 함수를 실행할 수 있게 되었지만, 이로 인해 더 많은 혼란 야기
함수 표현식은 변수 선언부만 호이스팅, 함수 표현식은 함수를 다른 변수에 값으로써 '할당'한 것이기 때문.
스코프
: 식별자에 대한 유효범위스코프 체인
: 식별자의 유효범위를 안에서 바깥으로 차례로 검색해나가는 것, 이를 가능하게 하는 것이 LexicalEnvironment의 OuterEnvironmentReference임OuterEnvironmentRecord
: 현재 호출된 함수가 선언될 당시의 LexcialEnvironment를 참조
var a = 1;
var outer = function(){
var inner = function(){
console.log(a); // 1) undefined
var a = 3;
}
inner();
console.log(a); // 2) 1
}
outer();
console.log(a); // 3) 1
위의 코드에서 inner 스코프의 LexicalEnvironment에 a 식별자가 존재하므로 스코프체인 검색을 더 진해하지 않음. inner 함수 내부에서는 전역공간에서 선언한 동일한 이름의 a변수에는 접근할 수 없음. 이를 변수 은닉화
라고 함