실행 컨텍스트

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) 순서

  1. js파일 최초 실행 시점에 전역 컨텍스트가 활성화되고 Call Stack에 push
  2. outer함수가 실행된 후 js엔진은 outer함수에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성 후 Call Stack에 push
  3. outer 내부의 inner 함수가 실행되며 inner 컨텍스트를 Call Stack에 push
  4. inner, outer, 전역 컨텍스트가 차례대로 실행되며 실행이 끝나는대로 Call Stack에서 pop

image

3) 구성

image

생성 단계(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함수가 모두 함수 선언문이기 때문에 최하단에 구현된 함수만 실행하게됨(오버로딩이 안됨)

댓글남기기