[JavaScript] 실행 컨텍스트

Taemin Jang·2023년 2월 25일
1

Javascript

목록 보기
4/14
post-thumbnail

실행 컨텍스트 (Execution Context)?

소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 객체로 관리하는 영역입니다.

⇒ 소스 코드 작성 및 실행은 실행 컨텍스트 내부에서 실행되고 있는 것 입니다.

종류

  1. 글로벌 실행 컨텍스트 (Global Execution Context, GEC)

    코드를 실행하며 단 한 개만 정의되는 전역 Context입니다. Global Object를 생성하며 this 값에 Global Object를 참조합니다. 또한 GEC는 자바스크립트 엔진이 스크립트 파일을 실행하기 전에 Call Stack에 가장 먼저 추가되어 앱이 종료될 때 삭제됩니다. (스택의 특징인 LIFO가 해당됩니다.)

  2. 함수 실행 컨텍스트 (Function Execution Context, FEC)

    함수가 실행 될 때마다 정의되는 Context입니다. GEC와 달리 FEC는 매 실행시마다 정의되며 함수 실행이 종료되면 Call Stack에서 제거됩니다.

  3. Eval Context

    eval()로 실행한 코드의 Context입니다. 보안상 취약한 점이 있어 잘 사용하지 않기 때문에 더 알아보진 않겠습니다.

Call Stack

자바스크립트는 단일 스레드이기 때문에 실행 컨텍스트가 실행되면 하나의 Call Stack에 실행 컨텍스트 스택이 쌓이게 됩니다.

GEC 코드를 실행하기 전에 Call Stack에 쌓이고, 함수가 실행되면 GEC 위에 FEC가 쌓이고, 함수가 종료되면 GEC가 제거되고 모든 코드가 종료되면 GEC가 마지막으로 제거된다.

https://miro.medium.com/max/1100/1*dUl6qPEaDJJTXWythQsEtQ.gif

구성요소

Lexical Environment, Variable Environment

변수 및 함수의 식별자 및 외부 참조에 관한 정보를 가지고 있는 컴포넌트입니다.

Variable Environment와 동일한 성격을 가지지만 var로 선언된 변수만 저장한다면 Lexical Environment는 let과 const로 선언된 변수를 저장합니다.

컴포넌트는 2개의 구성 요소를 갖습니다.

  • Environment Record
    • 식별자에 관한 정보를 가지고 있습니다.
  • outer 참조
    • 외부 Lexical Environment를 참조하는 포인터입니다.
var a = 3;
let b = 4;

function func(num) {
  var t = 9;
  console.log(a + b + num + t);
}

var r = func(4);
globalEnvironment : {
	LexicalEnvironment : {
		EnvironmentRecord : { 
			b: 4,
			r: func()
		 },
		outer: null
	}
	VariableEnvironment : {
		EnvironmentRecord : { a: 3 },
		outer: null
	}
}
funcEnvironment : {
	LexicalEnvironment : {
		EnvironmentRecord : { 
			arguments: { num: 4, length: 1 }
		 },
		outer: null
	}
	VariableEnvironment : {
		EnvironmentRecord : { t: 9 },
		outer: globalEnvironment
	}
}

func()에서 a, b를 참조할 때 Environment Record를 찾아보고 없으면 outer 참조를 통해 외부 Lexical Environment와 Variable Environment에 있는 Environment Record를 찾아보는 방식입니다.

this 바인딩

this 바인딩은 실행 컨텍스트가 생성될 때마다 this 객체에 어떻게 바인딩이 되는지를 나타낸 것입니다. ES6부터 LexicalEnvironment 안에 있는 Environment Record 안에서 일어납니다.

  • GEC의 경우
    • strict mode라면 undefined로 바인딩됩니다.
    • 아니라면 글로벌 객체로 바인딩됩니다. (브라우저에서는 window, 노드에서는 global)
  • FEC의 경우
    • 해당 함수가 어떻게 호출되었는지에 따라 바인딩됩니다.
const person ={
	name: "hansol",
	birthYear: 1988,
	calcAge: function(){
		console.log(2020 - this.birthYear);
	}
}

person.calcAge();//32 ---(1)

const calculateAge = person.calcAge;
calculateAge();//NaN ---(2)

(1) calcAge()는 person을 참조객체로 호출했기 때문에 this는 person을 가리키게 됩니다.

따라서 this.birthYear는 1988이므로 32가 출력됩니다.

(2) calculateAge()는 참조객체가 없기 때문에 this는 window를 가리키게 되고 전역객체(window)에는 birthYear라는 값이 없기 때문에 NaN이 출력됩니다.

로직

자바스크립트 엔진이 실행 컨텍스트를 만드는 과정에 대해 알아보겠습니다.

1. Creation Phase (생성 단계)

생성단계는 3가지로 이루어집니다.

  1. Lexical Environment 생성
  2. Variable Environment 생성
  3. this 바인딩

여기서 주의할 점은 변수가 생성되지만 값은 매핑되지 않는다는 것 입니다.

var의 경우 undefined로 초기화되고, let, const인 경우는 아무값도 가지지 않습니다.

2. Execution Phase (실행 단계)

let a = 20;
const b = 30;
var c;

function multiply(e, f){
	var g = 20;
	return e * f * g;
}
c = multiply(20, 30);
  1. 위 코드가 실행될 때 자바스크립트 엔진은 GEC를 만들고 전역 변수 중 함수와, let, const는 Lexical Environment로 var는 Variable Environment로 Key와 Value로 매핑됩니다.

    GEC = {
    	LexicalEnvironment: {
    		EnvironmentRecord: {
    			Type: "Object",
    			a: < uninitialized >,
    			b: < uninitialized >,
    			multiply: < func >
    		}
    		outer: <null>
    		ThisBinding: <Global Object>
    	},
    
    	VariableEnvironment: {
    		EnvironmentRecord: {
    			Type: "Object",
    			c: undefined,
    		}
    		outer: <null>
    		ThisBinding: <Global Object>
    	}
    }
  2. GEC가 실행되는 동안 각각의 변수 할당이 수행됩니다.

    GEC = {
    	LexicalEnvironment: {
    		EnvironmentRecord: {
    			Type: "Object",
    			a: 20,
    			b: 30,
    			multiply: < func >
    		}
    		outer: <null>
    		ThisBinding: <Global Object>
    	},
    
    	VariableEnvironment: {
    		EnvironmentRecord: {
    			Type: "Object",
    			c: undefined,
    		}
    		outer: <null>
    		ThisBinding: <Global Object>
    	}
    }
  3. multyply(20,30) 함수가 호출되는 시점에서 새로운 FEC가 생성됩니다.

    FEC = {
    	LexicalEnvironment: {
    		EnvironmentRecord: {
    			Type: "Declarative",
    			Arguments: { e: 20, f: 30, length: 2},
    		},
    		outer: <GlobalLexicalEnvironment>,
    		ThisBinding: <Global Object or undefined>,
    	},
    
    	VariableEnvironment: {
    		EnvironmentRecord: {
    			Type: "Declarative",
    			g: undefined,
    		}
    		outer: <GlobalLexicalEnvironment>,
    		ThisBinding: <Global Object or undefined>
    	}
    }
  4. FEC가 실행되면서 각각 변수 할당이 수행됩니다.

    FEC = {
    	LexicalEnvironment: {
    		EnvironmentRecord: {
    			Type: "Declarative",
    			Arguments: { e: 20, f: 30, length: 2},
    		},
    		outer: <GlobalLexicalEnvironment>,
    		ThisBinding: <Global Object or undefined>,
    	},
    
    	VariableEnvironment: {
    		EnvironmentRecord: {
    			Type: "Declarative",
    			g: 20,
    		}
    		outer: <GlobalLexicalEnvironment>,
    		ThisBinding: <Global Object or undefined>
    	}
    }

함수가 완료되면 FEC가 제거되고, GEC에 업데이트가 됩니다. 그리고 모든 코드가 수행되면 GEC도 제거가 되고 프로그램이 종료됩니다.

https://miro.medium.com/max/1100/1*SBP65hdVDW5j0LuVryTiXw.gif

참고

실행 컨텍스트와 자바스크립트의 동작 원리

Must-Know-About-Frontend/execution-context.md at main · baeharam/Must-Know-About-Frontend

prepare_frontend_interview/js.md at main · junh0328/prepare_frontend_interview

profile
하루하루 공부한 내용 기록하기

0개의 댓글

관련 채용 정보