[Javascript] 자바스크립트 실행 컨텍스트 (Execution Context)

임홍원·2023년 10월 13일

실행 컨텍스트

자바스크립트의 실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다. 자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 다음과 같은 일을 한다.

  1. 선언된 변수를 위로 끌어올림 (호이스팅)
  2. 외부 환경정보 구성
  3. this 값 설정

실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.
그 객체. 즉, 동일 환경에 있는 코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고 ‘스택’의 한 종류인 콜스택에 쌓아올린다.
가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경 및 순서를 보장할 수 있다.


실행 컨텍스트 (Execution Context) 에 담기는 정보

1. VariableEnvironment

현재 컨텍스트의 내부의 식별자 정보 environmentRecord, 외부 환경 정보 outerEnvironmentReference 가 포함되어 있다.
VariableEnvironment 에 먼저 정보를 담고, 그대로 LexicalEnvironment 에 복사해 사용한다.

environmentRecord

현재 컨텍스트와 관련된 식별자와 식별자에 바인딩된 값이 기록되는 공간이다.
더불어 실행 컨텍스트 내부 전체를 처음부터 끝까지 확인하며 순서대로 수집한다.

outerEnvironmentReference

현재 호출된 함수가 선언될 당시의 LexicalEnvironment 를 참조한다.

2. LexicalEnvironment

  1. 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장(수집)
  2. 수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등
  3. 컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집

호이스팅

  1. 변수정보 수집을 모두 마쳤더라도 아직 실행 컨텍스트가 관여할 코드는 실행 전의 상태.(JS 엔진은 코드 실행 전 이미 모든 변수정보를 알고 있는 것)
  2. 변수 정보 수집 과정을 이해하기 쉽게 설명한 ‘가상 개념’
function a (x) { // 호이스팅 적용전
	console.log(x);
	var x;
	console.log(x);
	var x = 2;
	console.log(x);
}
a(1);
function a () { // 매개변수 적용
	var x = 1;
	console.log(x);
	var x;
	console.log(x);
	var x = 2;
	console.log(x);
}
a(1);
function a () { // 호이스팅 적용 후
	var x;
	var x;
	var x;

	x = 1;
	console.log(x);
	console.log(x);
	x = 2;
	console.log(x);
}
a(1);

호이스팅을 생각하지 않았다면 결과를 1-> undefined -> 2로 처음엔 예상했겠지만, 호이스팅 적용후 1 -> 1 -> 2 라는 결과가 나오게된다.
호이스팅은 마찬가지로 함수 선언문 전체를 호이스팅 한다.

function a () { //호이스팅 적용 전
	console.log(b);
	var b = 'bbb';
	console.log(b);
	function b() { }
	console.log(b);
}
a();
function a () {
	var b; // 변수 선언부 호이스팅
	function b() { } // 함수 선언은 전체를 호이스팅

	console.log(b);
	b = 'bbb'; // 변수의 할당부는 원래 자리에

	console.log(b);
	console.log(b);
}
a();

스코프 (Scope)와 스코프체이닝 (Scope chaining)

스코프란 식별자에 대한 유효 범위
스코프 체이닝은 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것

var a = 1;
var outer = function() {
	var inner = function() {
		console.log(a); // undefined
		var a = 3;
	};
	inner();
	console.log(a);  // 1
};
outer();
console.log(a); // 1
  1. outer는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조
  2. 예를 들어, A함수 내부에 B함수 선언 → B함수 내부에 C함수 선언(Linked List)한 경우 어떻게 될까?
  3. 결국 타고, 타고 올라가다 보면 전역 컨텍스트의 LexicalEnvironment를 참조한다.
  4. 항상 outer는 오직 자신이 선언된 시점의 LexicalEnvironment를 참조하고 있으므로, 가장 가까운 요소부터 차례대로 접근 가능
  5. 결론 : 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에게만 접근이 가능

3. ThisBinding

this 식별자가 바라보아야 할 객체
this는 실행 컨텍스트가 생성될 때 결정된다.
이 말을 this를 bind한다(=묶는다) 라고도 한다.
다시 말하면, this는 함수를 호출할 때 결정된다. 라고 할 수 있다.

메서드 에서 사용시 해당 메서드 가 담겨있는 instance or object 를 가르키며, 함수표현식에서 사용시 this 를 바인딩하지 않는 이상 전역 객체를 가르킨다.

ES6 의 화살표함수를 사용하면 this 바인딩, 우회법으로 변수에 this 를 담아 실행할 필요 없이 함수를 실행한 컨텍스트를 바라본다.

const obj = {
  outer: function () {
    console.log(this); // 메소드에서 사용되었기에 obj 출력
    function inner() {
      console.log(this); // 함수표현식에서 사용되었기에 전역객체 출력
    }
    inner();

    const self = this;
    function inner2() {
      console.log(self);  // 우회하기위해 this 를 self 에 할당, 출력하였기에 obj 출력
    }
    inner2();
    const inner3 = () => {
      console.log(this);  // 화살표함수 사용으로 this 는 상위 스코프의 컨텍스트를 가르킴, obj 출력
    };
    inner3();
  },
};

obj.outer();
//	outer =>[object Object]
///	inner =>[object global]
//	inner2 =>[object Object]
//	inner3 =>[object Object]
profile
Frontend Developer

0개의 댓글