모던 자바스크립트 스터디 23장

lamPolar·2024년 3월 15일
0

javascript

목록 보기
1/5
post-thumbnail

실행컨텍스트 execution context

실행컨텍스트를 이해하면 자바스크립트의 동작원리를 이해할 수 있다. 키야
1. 스코프를 기반으로 식별자와 식별자에 바인딩된 값 (식별자 바인딩)을 관리하는 방식
2. 호이스팅이 발생하는 이유
3. 클로저의 동작방식
4. 태스크큐와 함께 동작하는 이벤트 핸들러
5. 비동기 처리의 동작방식
을 모두 이해할 수 있다~~
이 장에 대한 이해를 끝낸 뒤에 다시 생각해보자~

23.1 소스코드의 타입

ECMAScript사양은 소스코드를 4가지 타입으로 구분

  1. 전역코드 (global code)
  • 전역에 존재하는 소스코드.
  • 전역에 정의된 함수, 클래스등의 내부 코드는 포함 x
  1. 함수코드 (function code)
  • 함수 내부에 존재하는 소스코드
  • 함수내부에 중첩된 함수, 클래스등의 내부 코드는 포함 x
  1. eval 코드 (eval code)
  • 빌트인 전역함수인 eval함수에 인수로 전달되어 실행되는 소스코드
  1. 모듈 코드 (module code)
  • 모듈 내부에 존재하는 소스코드
  • 모듈 내부의 함수, 클래스등의 내부 코드는 포함 x

각 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리 내용이 다름

  1. 전역 코드 -> 전역 실행 컨텍스트
  • 최상위 스코프인 전역 스코프를 생성.
  • var 키워드로 선언된 전역 변수와 함수선언문으로 정의된 전역함수를 전역객체의 프로퍼티와 메서드로 바인딩하고 참조하기 위해 전역객체와 연결
  1. 함수 코드 -> 함수 실행 컨텍스트
  • 지역 변수, 매개변수, arguments 객체를 관리
  • 생성한 지역 스코프를 스코프 체인에 연결
  1. eval 코드 -> eval 실행 컨텍스트
  • strict mode에서 자신만의 독자적인 스코프를 생성
  1. 모듈 코드 -> 모듈 실행 컨텍스트
  • module별로 독립적인 모듈 스코프를 생성

-> 여기서 eval과 module은 다음에 다루기로.
전역 실행 컨텍스트, 함수 실행 컨텍스트를 위주로 진행함.

23.2 소스코드의 평가와 실행

소스코드 평가과정 :

  • 실행컨텍스트 생성
  • 선언문 실행
  • 식별자를 기로 실행 컨텍스트가 관리하는 스코프에 등록

소스코드 실행과정 :

  • 실행에 필요한 정보 (변수, 함수의 참조)를 실행 컨텍스트가 관리하는 스코프에서 검색해서 취득
  • 변수값의 변경등 실행의 결과를 실행 컨텍스트가 관리하는 스코프에 등록
var x = 1;

평가하는 과정 : 실행컨텍스트가 관리하는 스코프에 등록, undefined로 초기화
x : undefined

실행하는 과정 : x 변수의 등록 확인, 실행 결과 값 등록
x : 1

23.3 실행 컨텍스트의 역할

전역코드와 함수코드로 구성된 예제 >

// 전역 변수 x, y 선언 
const x = 1;
const x = 2;

function foo(a){
  // 지역변수 x, y 선언
  const x = 10;
  const y = 20;
  
  console.log(a + x + y);
}
foo(100); // foo의 호출 순간 ①

console.log(x + y); // 3

Q. 이 코드의 평가 및 실행 순서는 어떻게 될까?

내 생각 :
1. foo , local x, local y, global x, global y 가 실행 컨텍스트에 등록
2. x = 1, y = 2 전역 변수를 각각 실행해서 찾아서 값을 변경
3. foo(100)호출
4. x = 10, y = 20 지역변수를 각각 실행해서 찾아서 값을 변경
5. console.log(a + x + y)실행
6. console.log(x + y)실행

이렇게 되지 않을까 생각했다.
책을 읽어보니, 함수 호출의 순간, 함수의 실행 컨텍스트가 만들어진다고 한다.
내가 1번으로 진행될 것이라고 생각한 local x, local y 가 3번 foo(100)호출 이후에 진행된다는 것이다.

그래서 실행 순서는 다음과 같다.
1. 전역 코드 평가
2. 전역 코드 실행
3. 함수 코드 평가
4. 함수 코드 실행
5. 함수 코드가 끝나면 다시 전역 코드 실행

이처럼 코드가 실행되려면 스코프, 식별자, 코드 실행 순서등의 관리가 필요하다.
이걸 해주는건 실행컨텍스트~
실행 컨텍스트는 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역이다.
식별자와 스코프는 렉시컬 환경으로 관리하고, 코드 실행 순서는 실행컨텍스트 스택으로 관리한다.

23.4 실행 컨텍스트 스택

제목에서 스포를 당했지만, 실행 컨텍스트는 스택 자료구조로 관리된다.
코드가 실행되는 시간의 흐름에 따라 실행 컨텍스트가 추가되고, 제거 된다.

함수의 실행시점에 함수의 실행 컨텍스트가 생성되고 실행 컨텍스트 스택에 추가되고,
함수의 종료 시점에 함수의 실행 컨텍스트를 제거하고(pop), 이전 실행 컨텍스트를 실행한다.
말로 설명하면 어려움 (그림을 보자 23-5)

23.5 렉시컬 환경

Lexical Environment는 식별자와 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 기록하는 자료구조이다.

사실, lexical Environtment 컴포넌트와 variable Environment 컴포넌트로 구성되는데, 하나의 동일한 렉시컬 환경을 참조한다.

Q. 그렇다면 variable Environment 컴포넌트가 필요한 이유는 뭘까?

아무튼, 렉시컬 환경은
1. 환경 레코드 (Environment Record)
스코프에 포함된 식별자를 등록
등록된 식별자에 바인딩된 값을 관리하는 저장소
2. 외부 렉시컬 환경에 대한 참조 (Outer Lexical Environment Reference)
상위 스코프를 가리킴 = 상위 코드의 렉시컬 환경
단방향 링크드 리스트인 스코프 체인을 구현함

이렇게 두개로 구성된다.

23.6 실행 컨텍스트의 생성과 식별자 검색 과정

이 단원에서는 이거 두개만 알면 된다.
1. 실행 컨텍스트가 생성되고 코드 실행 결과가 관리되는 방법
2. 실행 컨텍스트를 통해 식별자를 검색하는 방법

var x =1 ;
const y = 2; 

function foo (a){
  var x = 3;
  const y = 4;
  
  function bar (b){
  	const z = 5;
    console.log(a+b+x+y+z);
  }
  bar(10);
}
foo(20);

이 코드를 실행하기 위한 전체적인 순서는 다음과 같다.

  1. 전역 객체의 생성

  2. 전역 코드의 평가

    전역 코드의 평가는 다음과 같은 순서로 진행된다.

    1. 전역 실행 컨텍스트 생성
    2. 전역 렉시컬 환경 생성
      2.1. 전역 환경 레코드 생성
      ㄴ2.1.1. 객체 환경 레코드 생성
      ㄴ2.1.2. 선언적 환경 레코드 생성
      2.2. this 바인딩
      2.3. 외부적 렉시컬 환경에 대한 참조 결정
  3. 전역 코드의 실행

  4. foo 함수 코드 평가

    함수 코드 평가는 다음과 같은 순서로 진행된다.

    1. 함수 실행 컨텍스트 생성
    2. 함수 렉시컬 환경 생성
      2.1. 함수 환경 레코드 생성
      2.2. this 바인딩
      2.3. 외부 렉시컬 황경에 대한 참조 결정
  5. foo 함수 코드 실행

  6. bar 함수 코드 평가

  7. bar 함수 코드 실행

    console.log(a+ b+x+y+z)실행

    1. console 식별자 검색
    2. log 메소드 검색
    3. 표현식 a+b+x+y+z의 평가
  8. bar 함수 코드 실행 종료

  9. foo 함수 코드 실행 종료

  10. 전역 코드 실행 종료

이렇게 10단계의 순서가 끝나면 실행 컨텍스트에 아무것도 남아있지 않게 된다.

23.7 실행 컨텍스트와 블록 레벨 스코프

var 로 선언한 변수 : 함수레벨 스코프
let, const 변수 : 블록레벨 스코프

이때, 블록레벨 스코프를 생성하기 위해 선언적 환경 레코드를 갖는 렉시컬 환경을 새롭게 생성하여 기존의 렉시컬 환경을 교체한다. 새롭게 생성된 코드 블럭을 위한 렉시컬 환경의 외부 렉시컬 환경에 대한 참조는 교체하기 이전의 렉시컬 환경을 가리킨다.
-> 따라서 스코프 체인이 끊기지 않고 이어짐!

for (let i = 0; i < 5; i++){} 와 같이 for 문의 변수 선언문에 let키워드를 사용하면, 코드블록이 반복해서 실행될 때마다 코드블록을 위한 새로운 렉시컬 환경을 생성하고, for문이 포함된 상위 스코프와 독립적인 렉시컬 환경을 생성해 식별자의 값을 유지한다.

profile
불안을 안고 구르는 작은 모난 돌

0개의 댓글