Execute context(실행 컨텍스트) 기초

isthis·2022년 3월 30일
0
post-thumbnail

Execute context

먼저, javascript는 변수를 부르면 Scope라는 곳에서 찾게 된다.

💡 Scope란?

  • Scope means area, space, or region.
    변수의 유효범위를 나타내는 용어
  • Global scope means global space or a public space.
  • Local scope means a local region or a restricted region.
 function fn1() {
    n1 = "n1"; //1번 코드
    var v1 = "v1"; //2번 코드
    let l1 = "l1"; //3번 코드
    const c1 = "c1"; //4번 코드
    fn2();
  }
  fn1();

디버깅을 통해 위 코드를 한 줄 한 줄 실행시켜보자.
fn1 함수에 들어가게 되면, 아래 사진과 같이 Call Stack이라는 곳에 Execute context들이 쌓이게 된다.
비유를 들어 설명해보면, Call Stack을 폴더라고 하고 Scope들을 파일이라 해보자. fn1 폴더에서 접근할 수 있는 파일들이 fn1의 Scope들인 것이다. 따라서, 최초에 생기는 Execute context인 anonymous는 전역에서 접근 가능한 Execute context이기에 Global Execute context라고도 부른다. 즉, 메인 코드에서 함수 밖에서 선언한 것들은 global execute context에서 선언한 것들이다.
이를 통해 Execute Context란 Call Stack 내에 쌓이는 것들이라는 것을 알 수 있다.

(1번째 사진 : fn1 밖의 코드들이 접근할 수 있는 Scope 목록)
(2번째 사진 : fn1 함수 내에서 접근할 수 있는 Scope 목록)

또한, global execute context 범위에서 변수 선언을 할 때,
var 또는 아무것도 붙이지 않으면 Global scope에 변수로 저장되고,
let, const로 선언 시에는 Script scope에 저장된다.

alert(1)과 window.alert(1)을 콘솔 창에서 실행시켜보면 어떻게 될까.
결과는 동일하다. window 객체라는 것은 Global 객체(Global Scope)와 동일하기 때문이다. 따라서, alert는 global scope(window 객체)에 지정되어 있기 때문에 window객체로 불러도 동일한 값이다.
반면, let과 const로 선언한 변수의 경우는 Script scope에 저장되어 있다. 따라서, window(global scope) 객체를 통해 부를 수 없다.

위 사진의 fn1 execute context 안으로 들어가서 Scope을 보면, Local이라는 Scope가 추가된 것을 볼 수 있다. 그 후, fn1 함수 내의 1번 코드를 실행시키면 global scope에 n1이 선언된다.

이번엔 2번 코드를 실행시켜보자. Local Scope에 v1이 생성된 것을 볼 수 있다.
그 후, console에 v1, v0를 실행시켜보면 결과값이 나온다. v1은 fn1 Execute context의 Local Scope에서 찾아서 나온 것이고, v0는 Local Scope 탐색 후 Script Scope 탐색 후 Global Scope에서 찾아서 나온 것이다.
이처럼 Scope들이 연결되어 있는 것을 Scope Chain이라 한다.
마지막으로, 3번, 4번 코드는 실행 시 Local Scope에 지정된다.

💡 Global과 Script scope의 차이는?

window 객체로 된 환경변수(old style) + lexical로 선언하는 환경변수(new style) 두가지를 합쳐서 글로벌 환경변수로 본다. 후자의 경우, Script라는 scope로 분리해서 표기한다. let 과 const는 후자이기때문에 글로벌 환경이지만 window객체에는 들어있지 않다고 한다.
출처 : stackoverflow

let과 const는 비교적 최근에 도입된 문법이다. 추론하기엔 브라우저 js에서 global은 window 가 담당하는데, 이 영역은 이미 많은 변수들로 붐비고 있는 중이다. 여기에 사용자 정의 전역변수 혹은 상수까지 입장하게 된다면 여러가지 문제가 생길 수 있기 때문에, 이런 문제를 방지하기 위해서 사용자 정의 데이터를 담을 전용 글로벌 스콥이 생긴 것이 아닐까라고 추론하고 있다.
출처 : 생활코딩

💡 global scope 선언의 문제점

global scope에는 이미 다양한 값들이 선언되어 있다. 거기에 라이브러리 등을 포함시키면 더욱 많은 값들이 존재하게 되는데, 선언까지 해버리면 이름이 바뀌거나 지우거나 하는 안 좋은 일들이 생기게 된다. 따라서, 큰 프로그램을 제작할 땐 global scope에 선언하는 것은 바람직하지 않다.

fn2 함수로 들어가보자.

	n0 = "n0";
  var v0 = "v0";
  let l0 = "l0";
  const c0 = "c0";
  console.log(v0, n0, l0, c0);
  console.log(window.v0, window.n0, window.l0, window.c0);
function fn2() {
    n2 = "n2";
    console.log(n0, n1, n2);
    var v2 = "v2";
    console.log(v0, v2);
    // console.log(v1)
    let l2 = "l2";
    console.log(l0, l2);
    // console.log(l1);
    const c2 = "c2;";
    console.log(c0, c2);
    // console.log(c1);
  }
  function fn1() {
    n1 = "n1";
    var v1 = "v1";
    let l1 = "l1";
    const c1 = "c1";
    fn2();
  }
  fn1();

(사진 : fn2 함수로 들어간 후의 변화)

위와 같이 변한 것을 볼 수 있다.
fn1() 안에서 실행한 fn2()를 보자. 부모라고도 할 수 있는 fn1()의 Local Scope은 fn2()의 Local에 들어있지 않고, fn2()의 Local만이 들어있다.(Lexical Scope에서 이유 설명)

이 상태(fn2 execute context 범위)에서 선언했던 변수들을 실행시켜보자. 위 코드의 fn2 console.log 부분이다.
n0, n1, n2, v0의 경우 global scope에 있기 때문에 정상적으로 실행된다.
v2의 경우 fn2 Local scope에 있기 때문에 정상적으로 실행된다.
v1의 경우 fn1 Local scope에 있기 때문에 접근 불가로 오류가 난다.
l0의 경우 Script scope에 있기 때문에 정상적으로 실행된다.
l2의 경우 fn2 Local scope에 있기 때문에 정상적으로 실행된다.
l1의 경우 fn1 Local scope에 있기 때문에 접근 불가로 오류가 난다.
c의 경우는 l과 마찬가지로 동작된다.

fn2()의 코드를 전부 실행하고 나가보자.

Call Stack에서 fn2 Execute context가 사라진다. fn1을 나갔을 때도 마찬가지로 fn1이 Call Stack에서 제거가 된고 global execute context만 남게 된다.

Lexical scope

javascript는 Lexical scope를 따르고 있다.
Lexical scope란 함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정된다는 것이다.
자바스크립트는 렉시컬 스코프를 따르므로 함수를 선언한 시점에 상위 스코프가 결정된다. 함수를 어디에서 호출하였는지는 스코프 결정에 아무런 의미를 주지 않는다.
즉, 함수의 호출로 상위 스코프가 결정된 것이 아니라 함수의 선언에 따라 상위 스코프가 결정된다.

Lexical scope에 따라 아래 코드의 결과를 예측해보자

var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // ?
bar(); // ?

위 예제의 함수 bar는 전역에 선언되었다. 따라서 함수 bar의 상위 스코프는 전역 스코프이고 위 예제는 전역 변수 x의 값 1을 두번 출력한다.

정리

let 과 const는 함수 뿐만 아니라, block 안에서도 Local Scope로 들어가게 된다.
이에 관해서는 추가 공부 예정.

위 내용을 통해 얻을 수 있는 효과

예상치 못한 문제가 생겼을 때, debugger를 통해 현재 상태를 파악하고, 문제 해결 전략을 키울 수 있다.

참고자료
생활코딩
Execution Context | PoiemaWeb

profile
공부

0개의 댓글