•
실행할 코드에 제공할 환경 정보들을 모아놓은 객체
•
자바스크립트의 동적 언어로서의 성격
◦
호이스팅
◦
외부 환경 정보 구성
◦
this 값 설정
실행 컨텍스트란?
•
스택 - 출입구가 하나, 선입후출
•
큐 - 출구와 입구가 따로, 선입선출
•
흐름
1.
동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트 구성
2.
콜 스택에 쌓음
3.
가장 위에 있는 컨텍스트 관련 코드 실행
•
eval를 제외하면 컨텍스트를 구성하는 방법은 함수 실행 뿐
•
예제
var a = 1;
function outer() {
function inner() {
console.log(a);
var a = 3;
}
inner();
console.log(a);
}
outer();
console.log(a);
JavaScript
복사
1.
전역 컨텍스트가 콜 스택에 담긴다.
2.
outer 함수 호출 부분을 만난다.
3.
outer 함수 관련 환경 정보를 수집 후 콜 스택에 담는다.
4.
outer 실행 컨텍스트가 콜 스택의 최상단에 있으므로, outer 함수 관련 코드를 실행한다.
5.
실행 도중 inner 함수 호출 부분을 만난다.
6.
innter 함수 관련 환경 정보를 수집 후 콜 스택에 담는다.
7.
inner 실행 컨텍스트가 콜 스택의 최상단에 있으므로, inner 함수 관련 코드를 실행한다.
8.
inner 코드 실행 종료 후 콜 스택에서 제거한다.
9.
outer 코드 실행 종료 후 콜 스택에서 제거한다.
10.
전역 코드 실행 종료 후 콜 스택에서 제거한다.
•
실행 컨텍스트 객체에 담겨져 있는 정보들
◦
VariableEnvironment
◦
LexicalEnvironment
◦
ThisBinding
VariableEnvironment
•
렉시컬 환경과 다르게 최초 실행 시 스냅샷을 유지
1.
실행 컨텍스트 생성 시 VariableEnvironment에 정보를 담는다.
2.
이를 그대로 복사하여 렉시컬 환경을 만든다.
3.
이후에는 렉시컬 환경을 주로 사용한다.
•
구성 요소
◦
environmentRecord
◦
outer-EnvironmentReference
LexicalEnvironment
•
어휘적 환경, 정적 환경, 사전적인 환경
•
컨텍스트를 구성하는 환경 정보들을 사전에서 접하는 느낌
environmentRecord와 호이스팅
•
environmentRecord - 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장 (순서대로 수집) → 값에는 전혀 관심이 없다.
◦
매개변수 이름
◦
함수 선언
◦
변수명 등
•
전역 실행 컨텍스트는 전역 개체를 활용 (window, global)
•
정보들이 수집되어도 실행이 된 것은 아님 → 코드가 실행된 것도 아닌데 해당 환경에 속한 코드의 변수명들을 모두 알고 있음 → 호이스팅
•
호이스팅 규칙 (이해를 돕기 위함)
function a (x) {
console.log(x); // 1
var x;
console.log(x); // 1 (undefined 아님)
var x = 2;
console.log(x); // 2
}
a(1);
JavaScript
복사
function a () {
var x = 1;
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);
JavaScript
복사
function a () {
var x;
var x;
var x;
x = 1;
console.log(x); // 1
console.log(x); // 1
x = 2;
console.log(x); // 2
}
a(1);
JavaScript
복사
•
예시 2
function a () {
console.log(b);
var b = bbb;
console.log(b);
function b () {};
console.log(b);
}
a();
JavaScript
복사
function a () {
var b;
function b () {};
console.log(b); // b 함수
b = bbb;
console.log(b); // bbb
console.log(b); // bbb
}
a();
JavaScript
복사
•
함수 선언문과 함수 표현식
◦
함수 선언문 - 정의만 존재하고 별도의 할당이 없음
◦
함수 표현식 - 정의한 함수를 별도의 변수에 할당
function a () {}
a();
var b = function () {}
b();
var c = function d () {}
c();
JavaScript
복사
•
함수 선언문, 표현식 예시
console.log(sum(1, 2)); // 3
console.log(multiply(3, 4)); // multiply is not a function
function sum (a, b) {
return a + b;
}
var multiply = function (a, b) {
return a * b;
}
JavaScript
복사
// 함수 선언문은 전체를 호이스팅
var sum = function sum (a, b) {
return a + b;
}
// 함수 표현식은 선언부만 호이스팅
var multiply;
console.log(sum(1, 2));
console.log(multiply(3, 4));
multiply = function (a, b) {
return a * b;
}
JavaScript
복사
•
결론
◦
함수 선언문 - 호이스팅 발생하여 선언 이전에 호출해도 실행됨 (권장하지 않음, 디버깅 어려움)
◦
함수 표현식 - 호이스팅 발생 x → 선언 이전에 호출하면 에러 발생
스코프, 스코프 체인, outerEnvironmentReference
•
스코프 - 식별자에 대한 유효범위
•
스코프 체인 - 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것
•
outerEnvironmentReference - 스코프 체인을 가능하게 하는 것
1.
스코프 체인
•
outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조
◦
예시 - A 함수 내부에 B 함수 선언, B 함수 내부에 C 함수 선언
▪
C의 outerEnvironmentReference는 B의 LexicalEnvironment 참조
→ 여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능!
•
예시
var a = 1;
var outer = function () {
var inner = function () {
console.log(a);
var a = 3;
};
inner();
console.log(a);
};
outer();
console.log(a);
JavaScript
복사
1.
전역 컨텍스트 활성화, 전역 컨텍스트의 environmentRecord에 a, outer 식별자 저장
2.
전역 컨텍스트의 outerEnvironmentReference 는 없음
3.
전역 스코프의 a, outer에 각각 1과 함수를 할당
4.
outer 함수 호출, 전역 컨텍스트 코드 중단, outer 실행 컨텍스트 활성화
5.
outer 실행 컨텍스트의 environmentRecord에 inner 식별자 저장, outer 실행 컨텍스트의 outerEnvironmentReference는 전역 컨텍스트의 LexicalEnvironment를 복사
6.
outer 스코프에 있는 변수 inner에 함수 할당
7.
inner 함수 호출, outer 실행 컨텍스트 코드 중단, inner 실행 컨텍스트 활성화
8.
inner 실행 컨텍스트의 environmentRecord에 a 식별자 저장, inner 실행 컨텍스트의 outerEnvironmentReference는 outer 함수 실행 컨텍스트의 LexicalEnvironment를 복사
9.
inner 스코프에 있는 변수 a에 3 할당
10.
inner 함수 실행 종료, inner 함수 실행 컨텍스트 콜 스택에서 제거, outer 함수 실행 컨텍스트 활성화
•
변수 은닉화
◦
같은 식별자를 지닌 변수가 전역, 지역에서 선언이 되면, 지역에서는 전역의 변수에 접근할 수 없는 것
•
전역변수와 지역변수
◦
전역변수 - 전역 공간에서 선언한 변수
◦
지역변수 - 함수 내부에서 선언한 변수
this
•
실행 컨텍스트의 thisBinding에는 this로 지정된 객체가 저장
•
this가 지정되지 않은 경우 전역 객체가 저장