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값에 접근하지 못하는 것이다.