Sparta/TIL

24.01.05 누네띠조 5일차 - 실행 컨텍스트

jskim4695 2024. 1. 5. 15:16

1. 실행 컨텍스트

실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.

i) 선언된 변수를 위로 끌어올림 = 호이스팅(hoisting)

ii) 외부 환경 정보를 구성

iii) this 값을 설정

 

1)스택 vs 큐

a. stack : Last In, First Out

b. queue : First In, First Out

스택은 바구니, 큐는 원통으로 생각할 것.

 

 

콜스택(call stack)

실행 컨텍스트가 동일 환경에 있는 코드를 실행할 때 필요한 환경정보들을 모아 컨텍스트를 구성하고 이것을 위에서 설명드린 스택의 한 종류인 콜스택에 쌓아 올린다. 가장 위에 쌓여 있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드 환경 및 순서를 보장할 수 있다.

 

2) 컨텍스트의 구성

a.구성방법(여러가지가 있지만 우리는 함수만 생각하면 된다.)

i. 전역공간

ii. eval() 함수

iii. 함수(우리가 흔히 실행컨텍스트를 구성하는 방법)

 

b.실행컨텍스트 구성 예시 코드

// ---- 1번
var a = 1;
function outer() {
	function inner() {
		console.log(a); //undefined
		var a = 3;
	}
	inner(); // ---- 2번
	console.log(a);
}
outer(); // ---- 3번
console.log(a);

 

위 코드는 아래 순서대로 진행이 됩니다.(콜스택이 쌓이는 실행컨텍스트에 의해 순서가 보장됨)

  코드실행

-> 전역(in) -> 전역(중단) -> outer(in)

-> outer(중단) + inner(in)

-> inner(out) + outer(재개)

->outer(out) + 전역(재개)

-> 코드 종료

 

결국, 특정 실행컨텍스트가 생성(=활성화)되는 시점이 콜 스택의 맨위에 쌓이는(공기에 노출되는) 순간을 의미

= 현재 실행할 코드가 해당 실행 컨텍스트가 관여하게 되는 시점.

 

2. 실행 컨텍스트의 객체(=담기는 정보)

1) Variable Environment

a. 현재 컨텍스트 내의 식별자정보(=record)를 갖고 있다.

ex)var a = 4 면 record는 'var a' 부분을 의미

b. 외부 환경 정보(=outer)를 갖고 있다.

c. 선전지점 Lexical Environment의 snapshot

 

2) Lexical Environment

VE와 LE는 담기는 항목이 완벽하게 동일하다. 하지만 VE는 snapshot을 유지하고 LE는 유지하지 않고 실시간으로 변경사항을 계속해서 반영한다.

즉, 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LE를 만들고 이후에는 주로 LE를 활용한다.

 

3) ThisBinding : this 식별자가 바라봐야 할 객체

 

3. 호이스팅 : 컨텍스트 내부를 처음부터 끝까시 순서대로 훑어가며 수짐

변수정보 수집을 모두 마쳤더라도 아직 실행컨텍스트가 관여한 코드는 실행전 (JS 엔진은 코드 실행 전 이미 모든 변수정보를 알고 있음)

1)매개변수 및 변수는 선언부를 호이스팅한다.

//action point 1 : 매개변수 다시 쓰기(JS 엔진은 똑같이 이해한다)
//action point 2 : 결과 예상하기
//action point 3 : hoisting 적용해본 후 결과를 다시 예상해보기

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

1 → undefined → 2로 예상했지만 다시 쓰면

//action point 1 : 매개변수 다시 쓰기(JS 엔진은 똑같이 이해한다)
//action point 2 : 결과 예상하기
//action point 3 : hoisting 적용해본 후 결과를 다시 예상해보기

function a () {
	var x;
	var x;
	var x;

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

 

1, 1, 2 라는 결과가 나왔네요.

 

2)함수 선언은 전체를 호이스팅한다.

//action point 1 : 결과 값 예상해보기
//action point 2 : hoisting 적용해본 후 결과를 다시 예상해보기

function a () {
	console.log(b);
	var b = 'bbb';
	console.log(b);
	function b() { }
	console.log(b);
}
a();

에러(또는 undefined), ‘bbb’, b함수로 예상했지만

//action point 1 : 결과 값 예상해보기
//action point 2 : hoisting 적용해본 후 결과를 다시 예상해보기

function a () {
	var b; // 변수 선언부 호이스팅
	var b = function b() { } // 함수 선언은 전체를 호이스팅

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

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

실제로는 b함수, ‘bbb’, ‘bbb’라는 결과가 나온다.

 

4. 스코프, 스코프체인, outerEnvironmentReference

1) 스코프 : 식별자에 대한 유효범위, 대부분의 언어에 존재

2) 스코프체인 : 식별자의 유효범위를 안에서 바깥으로 차례로 검색해나가는 것. inner-outer-global 순

3) outerEnvironmentReference(이하 outer) : 스코프 체인이 가능토록 하는 외부 환경의 참조정보

 

스코프 체인의 특징 

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

b. 항상 outer는 가장 가까운 요소부터 차례대로 접근이 가능하다

c. 스코프 체인 상에서 가장 먼저 발견된 식별자에게만 접근이 가능하다

// 아래 코드를 여러분이 직접 call stack을 그려가며 scope 관점에서 변수에 접근해보세요!
// 어려우신 분들은 강의를 한번 더 돌려보시기를 권장드려요 :)
var a = 1;
var outer = function() {
	var inner = function() {
		console.log(a); // 이 값은 뭐가 나올지 예상해보세요! 이유는 뭐죠? scope 관점에서!
		var a = 3;
	};
	inner();
	console.log(a); // 이 값은 또 뭐가 나올까요? 이유는요? scope 관점에서!
};
outer();
console.log(a); // 이 값은 뭐가 나올까요? 마찬가지로 이유도!

 

각각의 실행 컨택스트는 LE 안에 record와 outer를 가지고 있고, outer 내부에는 그 실행컨텍스트가 선언될 당시의 LE 정보가 다 들어 있으니 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있다.