2차 공부/TIL

24.07.23 콜/스택, 실행 컨텍스트

공대탈출 2024. 7. 23. 15:37

https://velog.io/@leejuhwan/스택STACK과-큐QUEUE시

실행 컨텍스트란 실행할 코드에 제공할 환경정보들을 모아놓은 객체이다. 이것들을 스택의 한 종류인 콜스택에 쌓아올리는데, 이를 통해 가장 위에 쌓인 컨텍스트와 관련된 코드를 먼저 실행하는 환경 및 순서를 보장할 수 있다.

// ---- 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);

 

 

1. 전역컨텍스트 in

2. outer()을 만나 전역 중단 후 outer컨텍스트 in

3. inner()을 만나 outer 중단 후 inner컨텍스트 in

4. inner()실행 후 inner컨텍스트 out

5. outer()재개 후 outer컨텍스트 out

6. 전역 재개 후 전역 out

7. 코드 종료


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

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

매개변수 x에 1이 들어가므로 1, var x;로 초기화했으므로 undefined, x=2로 재할당하였으므로 2가 출력될 것으로 예상된다.

 

이처럼 매개변수 x를 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();

실행결과는 어떨까? 호이스팅이 적용되었을 순서를 생각해보자.

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

예상과는 다르게 1,1,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();

이 함수를 예상해보자.

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

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

function a () {
	var b;
    function b() {};	// var b = function b() {} 와 동일
    console.log(b);	// f b()
    b='bbb'
    console.log(b)	// 'bbb'
    console.log(b)	// 'bbb'
}
a();

 

예상한 결과와 실제 결과가 다르다. 함수도 hoisting되기 때문이다.

하지만, 함수라고해서 다 hoisting되는 것은 아니다.


console.log(sum(1, 2));
console.log(multiply(3, 4));

function sum (a, b) { // 함수 선언문 sum
	return a + b;
}

var multiply = function (a, b) { // 함수 표현식 multiply
	return a + b;
}

함수 선언문은 그 자체로 선언을 하는 것이기 때문에 함수 자체가 hoisting되지만, 함수 표현식은 var multiply가 선언, function~~ 부분은 할당 이므로 hoisting되었을 때 사용하지 못한다.

...

console.log(sum(3, 4));

// 함수 선언문으로 짠 코드
// 100번째 줄 : 시니어 개발자 코드(활용하는 곳 -> 200군데)
// hoisting에 의해 함수 전체가 위로 쭉!
function sum (x, y) {
	return x + y;
}

...
...

var a = sum(1, 2);

...

// 함수 선언문으로 짠 코드
// 5000번째 줄 : 신입이 개발자 코드(활용하는 곳 -> 10군데)
// hoisting에 의해 함수 전체가 위로 쭉!
function sum (x, y) {
	return x + ' + ' + y + ' = ' + (x + y);
}

...

var c = sum(1, 2);

console.log(c);

선언문은 hoisting되었을 때 사용이 가능하기 때문에 예상치 못한 오류를 발생시킬 수 있다.

따라서 함수는 표현식으로 만들어 사용하는것이 더 안전한 방법이다.


// 아래 코드를 여러분이 직접 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); // 이 값은 뭐가 나올까요? 마찬가지로 이유도!

콜스택 순서에 의해 

1. inner함수 실행

2. var a; > console.log(a); > a = 3;

3. 이때 inner 실행컨텍스트가 out되어 outer함수에서 실행되는 console.log(a)는 1번줄의 var a = 1에서의 1이 출력된다.

 

항상 outer는 오직 자신이 선언된 시점의 LexicalEnvironment를 참조하므로 inner의 a값에 접근하지 못하는 것이다.