자바스크립트의 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
이다.
어떤 실행 컨텍스트가 활성화되는 시점에 다음과 같은 일을 한다.
호이스팅(hoisting)
this
값을 설정한다.코드를 실행하면서 생성되는 실행컨텍스트
를 저장하는 구조가 콜스택(Call Stack)
이다.
이름에서 알 수 있듯이 LIFO(Last In First Out)형태.
이해가 되지 않는다면 끝까지 읽고 처음부터 다시 읽어보자.
아래 코드 실행 결과를 예상해보자.
1 // (1) 전역(in)
2 var a = 1;
3 function outer() {
4 function inner() {
5 console.log(a); //undefined
6 var a = 3;
7 }
8 inner(); // (3) outer(중단) + inner(in)
9 console.log(a); // (4) inner(out) + outer(재개)
10 }
11 outer(); // (2) 전역(중단) + outer(in)
12 console.log(a); // (5) outer(out) + 전역(재개)
13 // (6)전역(out)
위 코드는 아래 순서로 진행.
(콜 스택에 쌓이는 실행컨텍스트 순서)
코드실행 → 전역(in) → 전역(중단) + outer(in) → outer(중단) + inner(in)
→ inner(out) + outer(재개) → outer(out) + 전역(재개) → 전역(out) → 코드종료
결과는 Undefined
, 1
,1
이 순서대로 출력 된다.
VariableEnvironment
1) 현재 컨텍스트 내의 식별자 정보(=record)
var a = 3
var a
를 의미2) 외부 환경 정보(=outer)
LexicalEnvironment
ThisBinding
이 두가지는 담기는 항목은 완벽하게 동일하다. 그러나, 스냅샷 유지여부가 다르다.
결론적으로 실행컨텍스트에 실행시점에만 두가지가 같고 이후 스냅샷 유지여부가 다르다.
environmentRecord(=Record)
호이스팅(Hoisting)
outerEnvironmentReference(=Outer)
this Binding
2, 3번 항목은 아래에서 설명 예정
호이스팅
은 "변수정보 수집을 모두 마친 상태" + "아직 실행 컨텍스트가 관여할 코드는 실행 전의 상태" 의 가상 개념.
(JS 엔진은 코드 실행 전 이미 모든 변수정보를 알고 있는 것)
호이스팅 법칙 1 : 매개변수 및 변수는 선언부를 호이스팅
적용 전
function a (x) {
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);
매개변수 적용
function a () {
var x = 1;
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);
// 예상 결과
// 1 → undefined → 2
호이스팅 적용
function a () {
var x;
var x;
var x;
x = 1;
console.log(x);
console.log(x);
x = 2;
console.log(x);
}
a(1);
// 실행 결과
// 1
// 1
// 2
호이스팅 법칙 2 : 함수 선언은 전체를 호이스팅
적용 전
function a () {
console.log(b);
var b = 'bbb';
console.log(b);
function b() { }
console.log(b);
}
a();
// 예상 결과
// undefined → 'bbb' → b함수
호이스팅 적용
function a () {
var b; // 변수 선언부 호이스팅
function b() { } // 함수 선언은 전체를 호이스팅
console.log(b);
b = 'bbb'; // 변수의 할당부는 원래 자리에
console.log(b);
console.log(b);
}
a();
// 실행 결과
// b함수 → 'bbb' → 'bbb'
var로 선언된 식별자는 호이스팅 시 undefined로 초기화 된다.
따라서 값이 할당되지 않아도 사용가능하며 에러가 나지 않는다.
그러나 let, const의 경우는 호이스팅 시 따로 초기화되지 않는다.
즉, 어떠한 값도 할당하지 않기 때문에 데이터 할당 전에 식별자를 사용하게 된다면 에러가 발생한다.
이 내용을 보면 알 수 있듯이 var를 사용하면 안전한 코드작성이 되기 어렵다.
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;
};
이렇게 함수 선언문
과 함수 표현식
은 hoisting
과정에서 극명한 차이가 생긴다.
여기서 함수 선언문
을 주의해야 하는데, 그 이유는 아래코드에서 볼 수 있다.
...
console.log(sum(3, 4));
// 함수 선언문으로 짠 코드
// 100번째 줄 : 시니어 개발자 코드(활용하는 곳 -> 200군데)
// hoisting에 의해 함수 전체가 위로 호이스팅
function sum (x, y) {
return x + y;
}
...
...
var a = sum(1, 2);
...
// 함수 선언문으로 짠 코드
// 5000번째 줄 : 신입이 개발자 코드(활용하는 곳 -> 10군데)
// hoisting에 의해 함수 전체가 위로 호이스팅
function sum (x, y) {
return x + ' + ' + y + ' = ' + (x + y);
}
...
var c = sum(1, 2);
console.log(c);
// 즉 시니어가 만든 sum함수가 신입 개발자가 만든 함수로 변경됨.
이걸 함수표현식으로 쓰게 된다면,
...
console.log(sum(3, 4));
// 함수 표현식으로 짠 코드
// 함수 선언부만 위로 호이스팅
// 이 이후부터의 코드만 영향을 받아요!
var sum = function (x, y) {
return x + y;
}
...
...
var a = sum(1, 2);
...
// 함수 표현식으로 짠 코드
// 함수 선언부만 위로 호이스팅
// 이 이후부터의 코드만 영향을 받아요!
var sum = function (x, y) {
return x + ' + ' + y + ' = ' + (x + y);
}
...
var c = sum(1, 2);
console.log(c);
// 즉, 함수가 변경된 시점부터 해당 함수가 적용된다.
복잡한 코드일수록, 전역 공간에서 이루어지는 코드 협업일수록 함수 표현식을 활용하는 습관이 중요함.
여기까지가 LE의 구성 중 environmentRecord(=Record)해당하는 부분이다.
이제 outerEnvironmentReference(=Outer)를 알아보자.
먼저 스코프(scope)
란 식별자에 대한 유효범위
를 의미한다.
스코프 체인은 변수 및 함수의 유효 범위를 나타내는 개념이다. 간단히 말하면, 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것.
function outer() {
var x = 10;
function inner() {
var y = 20;
function nested() {
var z = 30;
function deeplyNested() {
var w = 40;
console.log(x + y + z + w);
}
deeplyNested();
}
nested();
}
inner();
}
outer(); // 100 출력
위의 코드를 예시로 살펴보면,
deeplyNested()
함수 내에서 변수인 x,y,z,w
모두 사용이 가능하다. deeplyNested()
가 불린 곳 즉, nested()
에 외부에서 변수를 참조할 수 있기 때문에 이런 형식으로 스코프체인에 의해서 전부 참조가 가능하게 되는 것이다.
Outer
는 스코프 체인
이 가능토록 '외부 환경의 참조정보'
라고 할 수 있다.
스코프 체인
을 통해 사용할 수 있는 변수나 함수를 담고 있다고 보면 된다.
다시 말해, 현재 실행 컨텍스트에서 바로 외부 스코프에 있는 변수나 함수 혹은 스코프 체인을 통해 넘어온 변수나 함수를 사용할 수 있다는 것이다.
this
는 실행 컨텍스트가 생성될 때 결정된다. 이 말을 this
를 binding
한다 라고 함.
this에 관한 내용은 아래링크를 참고하자.
https://velog.io/@hanbyul1025/this-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0
여기까지 실행컨텍스트에 관한 내용 끝.