Execution Context를 마스터해보자

19603 단어 JavaScriptJavaScript

피드백 및 오류 수정은 항상 환영합니다. 꼭 이상하거나 잘못되어져 있는 내용들에 대해서는 딴지를 걸어주세요!🐶

Execution Context

Javascript 코드가 실행되는 환경의 추상적 개념. 실제 코드는 아니다, 단지 개념이다. (글에서 코드처럼 Execution Context의 내부 구조에 대하여 작성하지만, 이는 단지 이해를 돕기 위한 것으로 실제로 그렇게 되어 있지 않다.)

Execution Context의 종류; Global Context & Function Execution Context

  • Global Context

    브라우저가 스크립트를 로딩해서 실행하는 순간 생성되는 Execution Context로 한 프로그램에 하나의 Global Context만 존재한다.

  • Function Execution Context

    함수가 호출될 때 생성되는 Execution Context이다.

Call Stack

코드 실행중 실행 컨텍스트들이 저장되는 스택으로 LIFO(나중에 들어온게 먼저 나가는) 구조이다 . 나중에 들어오는 실행 컨텍스트가 그 전에 있던 애 위에 올라가고, 가장 위에 있는 애부터 JS 엔진이 실행한다. 실행이 완료되면 스택에서 실행 컨텍스트가 빠진다.

Execution Context는 2개의 단계로 이루어져 있다; Creation Phase & Execution Phase


Creation Phase

: Execution Context가 생성되는 단계로 Global Execution Context라면 브라우저가 로딩해서 실행하는 순간이고, Function Execution Context라면 함수가 불러와지는 순간이다.

Creation Phase에서 일어나는 일

1. LexicalEnvironment 요소가 생성된다.

2. VariableEnvironment 요소가 생성된다.


Lexical Environment

변수 및 함수등의 identifier-variable mapping 을 저장하는 구조이다. 여기서 identifier는 변수와 함수의 이름, variable은 변수의 값이나 오브젝트가 참조하는 reference이다.

Lexical Environment의 구성 요소

1. Environment Record

함수와 변수의 정의가 저장된 곳으로, 두가지 종류가 있다.

함수의 Lexical Environment에서는 Declarative environment record가 생기고, 글로벌 코드에 대한 Lexical Environment에서는 Object environment record가 생긴다.

Declarative environment record의 경우 전달인자에 대한 정보도 다음과 같이 저장한다.

function foo(a, b) {
  var c = a + b;
}
foo(2, 3);


Arguments: {0: 2, 1: 3, length: 2},

2. Reference to the outer environment

외부의 Lexical Environment에 접근이 가능하다는 것을 의미한다.

3. This Binding

해당 Execution Context의 this의 값이 정해진다.
- Global Execution COntext의 경우에는 this는 Global Object를 의미한다.
- Function Execution Context에서는 함수가 어떻게 호출되냐에 따라서 this값이 달라진다.

Lexical Environmet의 개념적 형태

Global Execution Context

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object", // Global이므로
      // identifier-variable mapping
    }
    outer: <null>, //Global Lexical Environment가 가장 외부 Lexical Environmet이다. 
    this: <global object> // 브라우저에서는 Window Object이다.
  }
}

Function Execution Context

FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative", // 함수이므로
      // identifier-variable mapping
    }
    outer: <Global or outer function environment reference>,
    this: <depends on how function is called>
  }
}

Variable Environment는 Lexical Environment의 일종으로 한가지 차이점을 제외하고 같은 구성 요소와 형태를 가진다. ES6에서 서술된 그 차이점은 Lexical Environment는 함수와 letconst로 정의된 변수들을 저장하고, Variable Environment는 var로 정의된 변수들만 저장한다.


Execution Context

코드를 위에서 아래로 읽으며 Creation Phase에서 Environment Record에 저장된 identifer들의 값 또는 reference 할당, 및 실행이 일어난다.


예제

주어진 코드

let a = 20;
const b = 30;
var c;
function multiply(e, f) {
 var g = 20;
 return e * f * g;
}
c = multiply(20, 30);

해당 프로그램의 Execution Context들의 Creation Phase를 나타내보자

스크립트가 실행되자마자 Global Execution Context가 생성될 것이다.

주의할 점은, multiply 함수는 변수 c에 대해 할당하는 Global Execution Context의 Execution Phase에 일어나므로, multiply 함수에 대한 Function Execution Context도 이때 생성된다.

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
  
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

앞서 얘기한 것과 같이 Global에서 var로 선언된 변수가 있으므로, Variable Environment도 함께 생성된다.

주목해야할 점은, 변수 a,b,c에 할당된 값들이다. 앞서 얘기하였듯이 변수에 대한 값 할당은 Execution Phase에 일어나므로, Creation Phase에서는 아직 아무 값도 전달 되지 않았다. 이러한 상황에서 let & constuninitialized, 즉 실제로 아무 값도 전달되지 않은 상태가 되고, varundefined, 값이 정의되지 않았지만, 값은 전달되어 있는 상태이다.

이 차이가 let & constvar로 정의된 변수들이 값이 정의되기 전에 호출되었을 때 다른 반응을 일으키게 된다.(hoisting)

해당 프로그램의 Execution Context들의 Execution Phase를 나타내보자

  1. 코드를 위에서 아래로 읽으며 값 할당을 한다.
GLobalExecutionContext {
	Lexcial Environment {
		Environment Record{
			Type: "Object",
			a : 20,
			b : 30,
			multiply: <func>
			}
			outer: <null>,
			ThisBinding: <Global Object>
		}
	Variable Environment {
		Environment Record {
			Type: "Object",
			c : undefined,
			}
			outer: <null>,
			ThisBinding: <Global Object>
		}
	}
  1. multiply 함수가 호출되면, multiply 함수에 대한 Execution Context가 생성된다.

2-1 multiply 함수에 대한 Execution Context의 Creation Phase

FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

2-2 multiply 함수에 대한 Execution Context의 Execution Phase

변수 g의 값 할당이 일어난다. 함수의 실행이 끝나면 반환된 값이 Global Execution Context의 c에 저장된다.

FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: 20
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

이미지 다이어그램

좋은 웹페이지 즐겨찾기