7 - 25 TIL(CS)

hoin_lee·2023년 7월 25일
0

TIL

목록 보기
204/236

typescript를 작성하며 TIL을 대신 했는데 CS공부를 추가하기 위해 따로 적어보려 한다.

javascript의 실행 컨텍스트

쉽게 코드의 실행 환경이라고 이해하면 된다.
실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.
JS는 동일한 환경에 있는 환경 정보들을 모은 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경과 순서를 보장한다.
FILO의 구조이기에 순서를 보장, 콜스택 내부에 쌓인 실행 컨텍스트의 정보를 통해 환경을 보장할 수 있는 것이다.
환경이란 전역공간이 될 수 있고, 함수 즉 함수 내부의 환경이 될 수도 있다.

var temp = 'temp';

function b (){
  console.log('안녕하세용');
}

function a (){
  b();
}

a();

처음 JS코드를 실행하는 순간 사진의 1번처럼 전역 컨텐스트가 콜스택에 담긴다
브라우저의 경우 window, node경우 global같은 객체를 사용할 수 있는 이유가 이때문이다.

  • (1) 콜스택엔 전역 컨텍스트를 제외하곤 다른 컨텍스트가 없기에 전역 컨텍스트와 관련된 코드를 진행합니다.
  • (2) 전역 컨텍스트와 관련된 코드를 진행 중 a함수를 실행하였기에 a 함수의 환경 정보들을 수집하여 a 실행 컨텍스트를 생성, 콜스택에 담습니다.
    콜스택 최상단에 a 실행 컨텍스트가 있기에 기존의 전역 컨텍스트와 관련된 코드의 실행을 일시적으로 중단한 후 a 실행 컨텍스트의 코드를 실행합니다.
  • (3) a 함수 내부에서 b 함수를 실행하였기에 b 함수의 환경 정보들을 수집, 실행 컨텍스트를 생성, 콜스택에 담습니다. 이전과 똑같이 콜스택 최상단에 b 실행 컨텍스트가 있기에 기존 a 실행 컨텍스트와 관련된 코드의 실행을 일시적 중단합니다.
  • (4) b 함수가 종료된 후 b 실행 컨텍스트가 콜스택에서 제거됩니다. 제거 후 콜스택 최상단에는 a 실행 컨텍스트가 있기에 이전에 중단된 지점부터 코드 진행이 재개됩니다.
  • (5) a 함수 또한 종료된 후 실행 컨텍스트가 콜스택에서 제거됩니다.
  • 이후엔 전역 공간에 실행할 코드가 남아있지 않다면 콜스택에서 전역 컨텍스트 또한 제거되며 콜스택에 아무 것도 남지 않은 상태로 종료됩니다.

실행 컨텍스트엔 어떤 정보가 담겨있나?

variable environment, lexical environment, this binding가 있다

VariableEnvironment

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

LexicalEnvironment

LexicalEnvironment 는 초기에는 VariableEnvironment 와 같지만 변경 사항이 실시간으로 적용됩니다.
즉, VariableEnvironment 초기 상태를 기억하고 있으며, LexicalEnvironment 최신 상태를 저장하고 있습니다.

environmentRecord

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

어려우니 코드 예시를 봐보자.

var gamguma = 'junhwan';

console.log(gamguma); // junhwan
console.log(gamguma); // undefined

var gamguma = 'junhwan'; 

JS를 처음 보시는 분은 이게 왜 실행이 돼? 라고 할 것이다. Reference error가 발생하지 않고 그대로 실행되어 undefined 출력하는 문제가 있다 이는 호이스팅과 관련이 있는데

호이스팅이란?

자바스크립트 엔진이 실행 컨텍스트를 구성할 때 environmentRecord 에 식별자의 정보를 수집합니다. 이러한 과정을 통해 엔진은 함수를 실행하기도 전에 해당 컨텍스트 내부의 변수명들을 이미 알고있습니다.
이렇기에 식별자들을 코드의 최상단으로 끌어올렸다! 라는 호이스팅이라는 개념이 생겨납니다. 물리적으로 끌어올린 것이 아닌, 실행 컨텍스트 관점에선 이미 식별자들의 정보를 알고 있으니 식별자 정보를 수집하는 과정을 이해하기 쉬운 방법으로 나타낸 추상화한 가상 개념입니다.
이를 개선하기 위해 var대신 letconst가 나오는 등 많은 변화가 있었다

결론 적으로 LexicalEnvironmentenvironmentRecord 의 경우 해당 컨텍스트 환경에 필요한 식별자와 식별자의 값이 기록되며, 함수 실행 시 실행 컨텍스트가 생성되므로 (함수 실행보다 environmentRecord 수집이 먼저 되므로) 변수와 같은 식별자를 끌어올리는 것과 같다 라는 개념의 호이스팅이 생겨났다

const hello = 'hello';

const gamguma = () => {
  const gamja = {
    age: 10,
    breed: 'yorkshire terrier'
  };
  const guma = {
    age: 4,
    breed: 'yorkshire terrier'
  };
  console.log(hello);
  console.log(gamja);
  console.log(guma);
}
gamguma(); //'hello', {age: 10, breed: 'yorkshire terrier'}, {age: 4, breed: 'yorkshire terrier'}
console.log(gamja); //ReferenceError: gamja is not defined
console.log(guma); //ReferenceError: guma is not defined

해당 코드의 함수 내부에선 외부의 hello가 접근 가능하며 당연히 내부에서 선언된 gamjaguma도 접근 가능하다.
하지만 외부에서 내부에 선언된 gamjaguma는 접근할 수 없는데 이는 outerEnvironmentReference 덕분에 가능하다.
outerEnvironmentReference 란 현재 호출된 함수가 선언될 당시의 LexicalEnvironment 를 참조합니다.
여기서 선언될 당시가 중요한데요, gamguma 함수가 선언될 당시의 outerEnvironmentReference 는 글로벌 실행 컨텍스트의 LexicalEnvironment 를 참조하고 있으며, 해당 환경의 environmentRecordhello 와 같은 변수의 정보들이 기록되어 있습니다.

그렇기에 함수 내부에선 outerEnvironmentReference 를 통해 상위 컨텍스트의 LexicalEnvironment 에 접근하여 environmentRecord 에서 변수인 hello 를 사용할 수 있게 되는 것입니다.

더불어 outerEnvironmentReference 는 오직 자신이 선언될 당시의 LexicalEnvironment 를 참조하기에 순차적으로만 접근이 가능하며, 여러 스코프에서 동일한 식별자를 생성하였다 하더라도 가장 먼저 발견된 식별자만 접근이 가능합니다.

ThisBinding

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

LexicalEnvironment 의 environmentRecord 에서 함수 표현식과 함수 선언식의 environmentRecord 수집 차이, 클로저, 비동기에 대해선 이젠어 한번 다뤄본 적 있지만
빼먹은 부분은 한번 더 확인해 봐야겠다

Reference

https://gamguma.dev/post/2022/04/js_execution_context

profile
https://mo-i-programmers.tistory.com/

0개의 댓글