2023년 6월 28일
이론JS
조회 : 433|2분 읽기

실행 컨텍스트

🏭 실행 컨텍스트(EC)

자바스크립트 코드가 실행되고 연산되는 범위를 나타내는 추상적인 개념.
실행할 코드에 제공할 환경 정보들을 모아놓은 객체(ECO)
아래와 같은 두 단계를 거쳐 생성된다.

1. Creation Phase

LexicalEnvironment 생성
  1. 변수-식별자 맵핑 구조
  2. 렉시컬 환경 정보가 계속 바뀜
Variable Environment 생성
  1. 해당 EC 안에서 변수 상태에 의해 생성된 바인딩을 보유하는 렉시컬 환경
  2. 렉시컬 환경 정보가 생성됐을 때 값을 유지

2. Execution Phase

변수 할당 끝나고 코드 실행


🌍 전역 실행 컨텍스트(GEC)

기본 실행 컨텍스트로 함수 내부에 없는 코드는 전역 컨텍스트에서 실행
⭐ 단 한 개만 정의되는 전역 Context
GEC의 this -> window(browser) | global(node)
JS 작동원리 Call Stack에서 제일 처음 들어가 있으며 FEC를 실행시킨다.

🔨 함수 실행 컨텍스트(FEC)

함수 실행(호출)될 때 마다 정의되고 GEC 위에 올라가 실행되는 Context
JS 작동원리의 Call Stack에서 실행되는 함수의 단위


Example

javascript
1let front = 'react';
2let back = 'spring';
3let browser = 'chrome';
4var appStack;
5
6function createApp(...stacks){
7	let devops = 'aws';
8  	stacks.push(devops, browser)
9    return stacks
10}
11
12appStack = createApp(front, back);

1. Execution Phase 전 GEC의 형태
일반 코드, 변수가 작동하는 것과 같이 동작한다.
처음 초기화를 하기 전에 선언

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 식별자 바인딩
      front: < uninitialized >,
      back: < uninitialized >,
      browser: < uninitialized >,
      createApp: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 식별자 바인딩
      appStack: < uninitialized >,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

2. 변수 할당이 끝난 후 GEC
선언한 변수에 값 초기화

GlobalExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      front: 'react',
      back: 'spring',
      browser: 'chrome',
      createApp: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      appStack: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

3. 함수가 호출된 FEC
함수 호출했으니 함수 실행하기 위해 렉시컬이 FEC로 넘어간다.
outer(GEC)에서 외부에 참조해야하는 값이 있는지 확인한다. 여기서는 하나의 바로 GEC를 참조하기 때문에 browser(만약 node.js라면 node) 값 있는지 확인

FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      Arguments: {front: 'react', back: 'spring', length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      stack: undefined
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

4. 실행 단계가 된 FEC
함수 실행 끝나고 다시 GEC로 렉시컬 넘어감

FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      Arguments: {front: 'react', back: 'spring', length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      stacks: ['react', 'spring', 'aws', 'chrome']
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

🎨 간단한 그림

  1. GEC 정의
  2. GEC 안에 있는 FEC 정의 후 실행
  3. GEC 위에 올라왔던 FEC 제거


🏇 Lexical Environment

Lexical 중첩 구조를 기반으로 특정 변수 및 함수에 대한 식별자(unique)의 연결을 정의
Environment Record과 null이 될 수 있는 Lexical 외부 환경 참조로 구성
함수 정의, 블록, try-catch 등 특정 구문 구조와 연결되며 코드가 평가 완료될 때마다 새로운 Lexical Environment 생성
각 렉시컬 환경은 세가지 모듈을 가짐

🧾 Environment Record

관련 렉시컬 환경범위 내에서 생성된 식별자 바인딩을 기록

🧱 outerEnvironmentReference (외부 환경 참조)

렉시컬 환경 값들이 논리적으로 중첩돼있는 모델을 사용함
내부(현재) 렉시컬 환경을 논리적으로 감싸고 있는 렉시컬 환경(외부)의 참조 -> 내부 렉시컬에서 외부 렉시컬의 변수에 접근할 수 있게 해줌

🔏 this binding

this의 값이 결정, 설정된다.
FEC에서 this는 함수가 어떻게 호출되는지에 달렸다.
객체 참조에 의해 호출되면 this의 값은 해당 객체로 설정된다. 아니라면 전역 객체나 undefined로 설정된다.


참고