자바스크립트의 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이며, 다음과 같은 일을 한다.
선언된 변수를 위로 끌어올림 = 호이스팅(hoisting)
외부 환경 정보를 구성
this 값을 설정
이런 현상들 때문에 JS에서는 다른 언어랑은 다른 특징들이 나타나게 되는 것
스택 vs 큐
스택(Stack) 바스켓 LIFO 마지막에 들어간게 처음으로 나온다.
큐(Queue) 원통 FIFO 첫번째로 들어간게 처음으로 나온다.
콜 스택
실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓은 객체인데 그 객체 즉, 동일 환경에 있는 코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고 ‘스택’의 한 종류인 콜스택에 쌓아올린다. 가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경 및 순서를 보장할 수 있다.
구성방법
함수(우리가 흔히 실행컨텍스트를 구성하는 방법)
전역공간
eval()함수
// ---- 1번
var a = 1;
function outer() {
function inner() {
console.log(a); //undefined
var a = 3;
}
inner(); // ---- 2번
console.log(a);
}
outer(); // ---- 3번
console.log(a);
var a = 1; // 선언
function outer() {
function inner() { // 선언
console.log(a); //undefined // 실행2
var a = 3;
}
inner(); // ---- 2번 // 실행1
console.log(a);
}
outer(); // ---- 3번 // 선언
console.log(a);
현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장(함수에 지정된 매개변수 식별자, 함수자체, var로 선언된 변수 식별자 등)
var a(식별자) = 3(변수) , var a를 의미
외부 환경 정보(=outer)를 갖는다.
outerEnvironmentReference(=outer)
VE, LE는 모든 것이 동일하지만 다음의 차이가 있다.
VE는 생길 때의 그 모습은 간직(선언 시점 LexicalEnvironment의 snapshot)하는 한편,
LE는 변경사항을 신시간으로 반영한다.
결국, 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LE를 만들고 이후에는 주로 LE를 활용한다.
ThisBinding
environmentRocord(=record)
현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장(수집), 기록된다고 이해
수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등
컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집(실행X)
💫호이스팅(의 개념은 recod에서 나옴)
정보 수집을 모두 마쳤더라도 아직 실행 컨텍스트가 관여할 코드는 실행 전의 상태
변수 정보 수집 과정을 이해하기 쉽게 설명한 ‘가상 개념’
자바스크립트 엔진이 그 함수 안에서 변수들을 수집하는 과정
호이스팅 법칙
1. 매개변수 및 변수는 선언부를 호이스팅한다.
예상) 1 → undefined → 2
실제_호이스팅결과) 1, 1, 2
2. 함수 선언은 전체를 호이스팅한다.
예상) 에러(또는 undefined), ‘bbb’, b함수
실제_호이스팅결과) b함수, ‘bbb’, ‘bbb’
함수라고 다 호이스팅되는 것은 아니다.
함수 정의의 3가지 방식
// 함수 선언문. 함수명 a가 곧 변수명
// function 정의부만 존재, 할당 명령이 없는 경우
function a () { /* ... */ }
a(); // 실행 ok
// 함수 표현식. 정의한 function을 별도 변수에 할당하는 경우
// (1) 익명함수표현식 : 변수명 b가 곧 변수명(일반적 case에요)
var b = function () { /* ... */ }
b(); // 실행 ok
// (2) 기명 함수 표현식 : 변수명은 c, 함수명은 d
// d()는 c() 안에서 재귀적으로 호출될 때만 사용 가능하므로 사용성에 대한 의문
var c = function d () { /* ... */ }
c(); // 실행 ok
d(); // 에러!
console.log(sum(1, 2));
console.log(multiply(3, 4));
function sum (a, b) { // 함수 선언문 sum
return a + b;
}
var multiply = function (a, b) { // 함수 표현식 multiply
return a + b;
}
▼▼
// 함수 선언문은 그 자체로 선언이기에 전체를 hoisting
function sum (a, b) { // 함수 선언문 sum
return a + b;
}
// 변수는 선언부만 hoisting
var multiply;
console.log(sum(1, 2));
console.log(multiply(3, 4));
multiply = function (a, b) { // 변수의 할당부는 원래 자리
return a + b;
};
💫함수 선언문을 이용해서 코드를 작성하게된다면 그 함수 선언문잉 나도 인지하지 못하는 사이에 호이스팅에 의해 위로 끌어올려져서 코드 전체에 영향을 끼치게 될 수 있다. 반면 표현식으로 작성한 경우에는 이 같은 위험과 무지에서 벗어날 수 있으므로 복잡하거나 전역 공간에서 이루어지는 코드 협업일수록 함수 표현식을 활용하는 습관이 중요하다.
스코프
식별자에 대한 유효범위를 의미(변수가 어디까지 영향을 미칠 수 있느냐), 대부분 언어에서 존재
스코프체인
식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것
각각의 실행 컨텍스트는 LE 안에 record와 outer를 가지고 있고, outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE정보(outer입장에서의 전역 컨테스트)가 다 들어있으니 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있다.