[Core Javascript] 실행 컨텍스트
실행 컨텍스트
1. 실행 컨텍스트란?
- 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
- 동일한 스코프에 있는 코드들을 실행할 때 필요한 환경 정보를 모아 구성됨
- 구성된 정보들을 Call Stack에 쌓아 실행 순서를 보장함
1) 종류
- 전역 공간 : 함수가 실행되지 않는 한 컨텍스트에서 실행
- 함수 : 함수가 실행될 때마다 실행 컨텍스트가 생성되고, 함수가 동작을 다하면 Call Stack에서 삭제됨
- eval() : eval함수만의 별도의 실행 컨텍스트를 가짐
2) 실행 컨텍스트의 Call Stack 순서와 기능
var a = 1; // 전역
function outer(){ // outer
function inner(){ // inner
console.log(a); // undefined
var a = 3;
console.log(a); // 3
}
inner();
console.log(a); // 1
}
outer();
console.log(a); // 1
2-1) 순서
- js파일 최초 실행 시점에 전역 컨텍스트가 활성화되고 Call Stack에 push
- outer함수가 실행된 후 js엔진은 outer함수에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성 후 Call Stack에 push
- outer 내부의 inner 함수가 실행되며 inner 컨텍스트를 Call Stack에 push
- inner, outer, 전역 컨텍스트가 차례대로 실행되며 실행이 끝나는대로 Call Stack에서 pop
3) 구성
생성 단계(Creation Phase)
- 실행 컨텍스트 생성
- 선언문만 실행해서 Environment Record에 기록
실행 단계(Execution Phase)
- 선언문 외 나머지 코드 순차적 실행
- Environment Record 참조하거나 업데이트
2. VariableEnvironment, LexicalEnvironment
1) 주요 개념
VariableEnvironment
- 실행 컨텍스트 생성 시 VariableEnvironment에 실행 정보를 먼저 저장
- 구성 요소
- Environment Record(Snapshot): 현재 실행 컨텍스트 내에서 호이스팅이 되는 요소(var, 함수 선언문 등) 저장
- outerEnvironment Reference(Snapshot)
LexicalEnvironment 구성 요소(정적 환경)
- VariableEnvironment에 저장된 실행 정보를 복사하여 LexicalEnvironment에 저장
- 구성 요소
- Environment Record: let,const로 선언된 변수 및 함수 선언문 저장
- outerEnvironment Reference : 이전 Lexical Environment를 가리킴
호이스팅
- Hoisting : 선언문이 최상단에 끌어올려진 것 같은 현상
자바스크립트 엔진이 먼저 전체 코드를 스캔하면서 변수 같은 정보를 실행 컨텍스트에 미리 기록해놓기 때문(기록 장소는 Environment Record)
- Environment Record : 식별자와 식별자에 바인딩된 값을 기록해두는 객체
2) 변수 호이스팅
var로 변수 선언 시 선언과 undefined 초기화가 동시에 이루어짐 ```javascript console.log(fruits); // undefined
var fruits = “apple”;
console.log(fruits); // apple
> let, const로 변수 선언 시 선언만 이루어짐
```javascript
// Temporal Dead Zone ~~
console.log(fruits); // Reference Error
// ~~ Temporal Dead Zone
const fruits = "apple";
console.log(fruits);
일시적 사각지대(Temporal Dead Zone)
- let이나 const로 선언했을 때, 선언 이전에 식별자를 참조할 수 없는 구역
3) 함수 호이스팅
console.log(fruits()); // Reference Error
// 함수 표현식(변수 호이스팅과 동일하게 동작)
const fruits = () =>{
return "apple";
};
console.log(fruits()); // apple
// 함수 선언문(선언과 동시에 함수가 생성되고 온전하게 환경 레코드에 저장해두기 때문에 선언 이전에도 함수를 사용할 수 있음)
function fruits(){
return "apple";
};
4) 스코프 체이닝
- 식별자 결정(Identifier Resolution)
- 코드에서 변수나 함수의 값을 결정하는 것
- 변수 섀도잉(Variable Shadowing)
- 동일한 식별자로 인해 상위 스코프에서 선언된 식별자의 값이 가려지는 현상
- 스코프 체인(Scope Chain)
- 식별자를 결정할 때 활용하는 스코프들의 연결리스트
var a = 1;
function outer(){
function inner(){
// inner 스코프에 a가 선언돼서 스코프 체이닝 없이 그대로 출력
console.log(a); // undefined
var a = 3;
console.log(a); // 3
}
inner();
// outer 스코프에 a가 없으므로 스코프 체이닝에 의해 상위 스코프의 a값을 출력
console.log(a); // 1
}
outer();
console.log(a); // 1
3. this
- 실행 컨텍스트의 thisBunding에 this로 지정된 객체가 저장됨
- 실행 컨텍스트 활성화 상태에서 this가 지정되지 않은 경우 this에는 전역 객체가 저장됨
- 함수를 호출하는 방법에 따라 this에 저장되는 대상이 달라짐
4. 참조
- https://www.youtube.com/watch?v=EWfujNzSUmw
- https://dkje.github.io/2020/08/30/ExecutionContext/
- https://velog.io/@marulloc/3-Lexical-Environment
5. Quiz
1) 하단 두 코드의 실행 결과와 출력되는 결과의 차이점은 무엇일까요?
console.log(fruits());
const fruits = () =>{
return "apple";
};
console.log(fruits());
var fruits = () =>{
return "apple";
};
2) 하단 코드의 실행 결과는?
function sum(a, b){
return a + b;
}
console.log(sum(1, 2));
function sum(a, b, c){
return a + "+" + b;
}
console.log(sum(1, 2));
5. Quiz
1) 하단 두 코드의 실행 결과와 출력되는 결과의 차이점은 무엇일까요?
console.log(fruits());
const fruits = () =>{
return "apple";
};
console.log(fruits());
var fruits = () =>{
return "apple";
};
A) 첫 번째는 Reference Error, 두 번째는 Type Error 발생
차이점 : 첫 번째는 fruits가 선언된 상태에서 아무 값이 없으며 두 번째는 fruits 선언 후에 undefined로 초기화 되었기 때문에 함수로 인식하지 못한다.
2) 하단 코드의 실행 결과는?
function sum(a, b){
return a + b;
}
console.log(sum(1, 2));
function sum(a, b, c){
return a + "+" + b;
}
console.log(sum(1, 2));
A) “1+2”가 두 번 출력됨, sum함수가 모두 함수 선언문이기 때문에 최하단에 구현된 함수만 실행하게됨(오버로딩이 안됨)
댓글남기기