# 23장 실행 컨텍스트

> ❗❗실행 컨텍스트는 자바스크립트의 동작 원리를 담고 있는 핵심 개념이다❗❗

*실행 컨텍스트를 바르게 이해하면 스코프를 기반으로, 식별자와 식별자에 바인딩 된 값(식별자 바인딩)을 관리하는 방식, 호이스팅이 발생하는 이유, 클로저의 동작 방식, 태스크 큐와 함께 동작하는 이벤트 핸들러와 비동기처리의 동작방식을 이해할 수 있다.*

> **스코프, 식별자, 식별자 바인딩, 클로저, 호이스팅, 태스크 큐, 비동기처리 동작방식**을 이해할 수있다

<br>

## 23.1 소스코드의 타입

> \
> 4가지 타입의 소스코드 - 실행 컨택스트 생성 (ECMAScript)\ <br>

<br>

| 소스코드 타입 | 설명                                                |
| ------- | ------------------------------------------------- |
| 전역 코드   | 전역에 존재하는 소스코드, 전역에 정의된 함수, 클래스는 포함하지 않음           |
| 함수 코드   | 함수 내부에 존재하는 소스코드, 함수 내부에 중첩된 코드, 클래스는 포함되지 않음     |
| eval 코드 | 빌트인 전역함수인 eval 함수에 인수로 전달되어 실행되는 소스코드.            |
| 모듈 코드   | 모듈 내부에 존재하는 소스코드, 모듈 내부의 함수, 클래스 등의 내부코드는 포함되지 않음 |

\ <br>

**소스코드를 네가지로 분류하는 이유?**\
📌 소스코드의 타입에 따라 실행 컨택스트를 생성하는 과정과 관리 내용이 다르기 때문이다

✅ 전역코드, 함수코드, eval코드, 모듈코드는 **평가** 될 때 각각의 실행 컨택스트 생성.

***1. 전역 코드***

> 전역 코드가 평가되면 전역 실행 컨텍스트 생성

1. 전역 변수를 관리하기 위해. 최상위 스코프인 전역 스코프 생성,
2. 전역 객체와 연결 - var 키워드로 생성된 전역변수 - 함수 선언문으로 정의된 전역변수 전역 객체 프로퍼티와 메서드로 바인딩\ <br>

***2. 함수 코드***

> 함수 코드가 평가되면 함수 실행 컨택스트가 생성됨

1. 지역 스코프 생성,
2. 지역 변수, 매개변수, arguments를 관리
3. 생성한 지역스코프를 전역 스코프에서 시작하는 스코프 체인의 일원으로 연결\ <br>

***3. eval 코드***

> eval코드가 평가되면 eval 실행 컨택스트 생성

1. strict mode에서 독자적인 스코프 생성\ <br>

***모듈 코드***

> 모듈 코드가 평가되면, 모듈 실행 컨택스트 생성

1. 모듈별로 독립적인 모듈 스코프생성

\
\ <br>

## 23.2 소스코드의 평가와 실행

> \
> 자바스크립트 엔진은 소스코드를 “소스코드의 평가”와 “소스코드의 실행” 두개의 과정으로 나누어 처리한다\ <br>

<br>

***소스코드의 평가***

1. 실행컨택스트 생성
2. 변수, 함수등의 선언문만 먼저 실행
3. 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록

> \
> ✅ 소스코드 평가과정
>
> ```
> 실행컨텍스트 생성 → 변수, 함수 선언문만 실행 → 실행 컨텍스트 스코프에 등록
> ```
>
> ✅ 소스코드평가 이후에 런타임이 실행된다 ( = 선언문 제외 소스코드가 순차적으로 실행된다)<br>

***예시***

```tsx
var x;
x = 1;
```

위 두개의 코드를 처리하는 과정

```
  소스코드의 평가 과정에서

1. 실행컨텍스트 생성,
2. var x;만 먼저 실행,
  → x라는 변수는 실행컨텍스트가 관리하는 스코프에 등록되고, undefined로 초기화됨
3. 소스코드 평가가 끝나면 소스코드 실행 과정이 실행된다

  소스코드 실행 과정에서

4. var x;는 이미 소스코드 평가 과정에서 실행완료 되었으므로, 실행 과정에서는 변수 할당문 x = 1;만 실행된다
  - 이때 x변수에 값을 할당되려면, x변수가 선언된 변수인지 확인해야함
  - 이를 위해 실행컨텍스트가 관리하는 스코프에 x변수가 등록되어있는지 확인한다
5. x가 실행 컨텍스트가 관리하는 스코프에 등록되어있다면?
  - x는 평가 과정에서 선언문이 실행되어 등록된 변수
6. x가 선언된 변수라면, 값을 할당하고, 할당 결과를 실행 컨텍스트에 등록해서 관리함
```

## 23.3 실행 컨텍스트의 역할

### 자바스크립트는 소스코드를 어떻게 평가하고 실행하나?

```tsx
const x = 1;
const y = 2;

function foo(a) {
  const x = 10;
  const y = 20;

  console.log(a + x + y);
}

foo(100);

console.log(x + y);
```

위와 같은 예제를 자바스크립트 엔진은 어떻게 평가, 실행하는지 살펴보면

***1. 전역 코드 평가***

* 전역 코드를 실행하기 앞서 전역 코드 평가 과정을 거친다
* 소스코드 평가 과정에서는 선언문만 먼저 실행함
  * 전역 코드의 변수 선언문과 함수 선언문이 먼저 실행되고, 그 결과로 생성된 전역변수와 전역 함수가 실행컨텍스트가 관리하는 전역 스코프에 등록
* var 키웓로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 프로퍼티와 메서드가 된다

***2. 전역 코드 실행***

* 전역 코드 평가 과정이 끝나면 런타임이 시작되어 전역 코드가 순차적으로 실행되기 시작함
* 전역변수에 값이 할당되고 함수가 호출됨
* 함수가 호출되면 전역 코드의 실행을 일시 중단하고, 코드 실행 순서를 변경하여 함수 내부로 진입

***3. 함수 코드 평가***

* 함수 호출로 코드 실행순서가 변경되어 함수 내부로 진입하면, 함수 내부의 문을 실행하기 앞서 함수 평가 과정을 거침
* 매개변수와 지역 변수 선언문이 먼저 실행됨
* 생성된 매개변수와 지역변수가 실행 컨텍스트가 관리하는 지역 스코프에 등록됨
* 함수 내부에서 지역변수처럼 사용되는 arguments 객체가 생성되어 지역 스코프에 등록되고, this 바인딩도 결정됨

***4. 함수 코드 실행***

* 함수 코드 평가가 끝나면 런타임이 시작되어 함수 코드가 순차적으로 실행됨, 매개변수와 지역변수에 값이 할당되고, console.log 메서드가 호출됨(코드에 console.log)
* console.log 메서드를 호출하기 위해, 식별자인 console을 스코프 체인을 통해 검색한다
  * 이를 위해 함수 코드의 지역 스코프는 상위 스코프인 전역 스코프와 연결되어야 한다. console 식별자는 스코프체인에 등록된게 아니라 전역 객체에 프로퍼티로 존재한다 (전역 객체의 프로퍼티가 전역 변수처럼 전역 스코프를 통해 검색 가능해야한다)
* log 프로퍼티를 console 객체의 프로토타입 체인을 통해 검색한다
  * console.log 메서드에 인수로 전달된 표현식 a + x + y가 평가된다, a,x,y 식별자는 스코프 체인을 통해 검색함
  * console.log 메서드 실행이 종료되면, 함수 코드 실행 과정이 종료되고, 함수 호출 이전으로 되돌아가 전역 코드 실행을 계속한다

***⭐️요약***

> \
> 💡 코드가 실행되려면, 스코프, 식별자, 코드실행 순서 등의 관리가 필요하다
>
> * 코드가 실행되려면, 스코프를 구분하여 식별자와 바인딩된 값이 구분되어야 한다.
> * 중첩 관계에 의해 스코프 체인을 형성하여 식별자를 검색할 수 있어야 함
> * 전역객체의 프로퍼티도 전역 변수처럼 검색할 수 있어야 한다
> * 또한 함수 호출이 종료되면, 함수 호출 이전으로 돌아가기 위해 현재 실행중인 코드와 이전에 실행하던 코드를 구분하여 관리해야 함<br>

***실행 컨텍스트가 관리하는 것***

1. 선언에 의해 생성된 모든 식별자(변수, 함수, 클래스)를 스코프를 구분하여 등록하고 상태 변화(식별자에 바인딩 된 값의 변화)를 지속적으로 관리할 수 있어야함
2. 스코프는 중첩 관계에 의해 스코프 체인을 형성해야 함

   스코프 체인을 통해 상위 스코프로 이동하여 식별자를 검색할 수 있어야함
3. 현재 실행중인 코드의 실행순서를 변경할수 있어야한다.

   ex) 함수 호출에 의한 실행순서 변경

> \
> 📌 실행 컨텍스트는 소스코드를 실행하는데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역 스코프 관리(식별자 등록 , 관리)와 실행 순서 관리를 구현한 내부 메커니즘이다.
>
> ```
> ✅ 모든 식별자에 대해 스코프 구분하여 등록,
> ✅ 변수의상태변화 지속적 관리
> ✅ 스코프 체인 형성
> ✅ 스코프코드 실행 순서 변경등등
> ```

> 📌 렉시컬 환경 + 실행 컨텍스트 스택<br>
>
> ✅ 식별자와 스코프는 실행 컨텍스트의 렉시컬 환경으로 관리하고, 코드 실행 순서는 실행 컨텍스트 스택으로 관리한다

## 23.4 실행 컨텍스트 스택

***예제로 실행 컨텍스트 스택 이해하기***

> 💡 코드 실행 순서를 결정하는 실행 컨텍스트는 스택 자료구조로 관리된다
>
> 전역 코드 평가 - 전역 코드 실행컨텍스트 생성 - 전역코드 실행 - 함수 호출되면 함수 실행 컨텍스트 생성 - 함수 실행 - …. 이런식으로 코드가 실행되는데 실행되는 시간의 흐름에 따라 컨텍스트가 push / pop 된다

```tsx
const x = 1;

function foo() {
  const y = 2;

  function bar() {
    const z = 3;
    console.log(x + y + z);
  }
  bar();
}

foo();
```

|  순서 |     1     |        2       |       3       |       4      |     5     |  6  |
| :-: | :-------: | :------------: | :-----------: | :----------: | :-------: | :-: |
|     |           |                | bar함수 실행 컨텍스트 |              |           |     |
|     |           | foo 함수 실행 컨텍스트 | foo함수 실행 컨텍스트 | foo함수 실행컨텍스트 |           |     |
|     | 전역 실행컨텍스트 |    전역 실행컨텍스트   |   전역 실행컨텍스트   |   전역 실행컨텍스트  | 전역 실행컨텍스트 |     |
|  >  |     >     |        >       |       >       |       >      |     >     |  >  |

💡 전역코드 { foo 코드 { bar 코드 }}

1. 전역 코드 평가와 실행
   * 전역 코드를 평가하여, 전역 실행 컨텍스트 생성
     * 실행 컨텍스트 스택에 푸시
     * 변수 x와 foo는 전역 실행 컨텍스트에 등록된다
   * 전역코드 평가가 끝나면 전역 코드 실행
   * 변수 x에 값이 할당되고, foo 함수 호출
2. foo 함수 코드 평가와 실행
   * 함수 foo가 호출되면, 전역 코드 실행이 일시 중단되고, 코드 제어권이 foo 함수 내부로 이동함
   * 자바스크립트 엔진이 foo 내부 코드를 평가
     * foo 함수 실행컨텍스트 생성,
     * 실행 컨텍스트 스택에 foo 실행컨텍스트 푸시
     * foo 함수의 지역변수 y와 중첩 함수 bar가 foo 함수 실행컨텍스트에 등록됨
   * foo함수 평가가 완료되면 foo 함수 실행
   * 지역변수 y에 값이 할당되고 중첩변수 bar가 호출됨
3. bar 함수 코드 평가와 실행
   * 중첩 함수 bar가 호출되면, foo 함수 코드 실행이 일시 중단되고, 코드의 제어권이 bar 함수 내부로 이동
   * 자바스크립트 엔진이 bar 내부 코드를 평가
     * bar 함수 실행컨택스트 생성,
     * 실행컨택스트 스택에 bar 함수 실행컨택스트 푸시
     * bar 함수의 지역변수 z가 bar 함수 실행컨텍스트에 등록
   * bar 함수 평가가 완료되면 bar 함수 실행
   * 지역변수 z에 값 할당, console.log 메서드 호출 후에 bar 함수 종료
4. foo 함수 코드로 복귀
   * bar함수가 종료되면, 코드의 제어권을 다시 foo함수로 이동
     * 실행 컨텍스트 스택에서 bar 함수의 실행컨텍스트 pop으로 제거
   * foo 함수도 더이상 실행할게 없으므로, 종료됨
5. 전역 코드로 복귀
   * foo함수가 종료되면, 코드의 제어권을 다시 전역코드로 이동
     * 실행컨텍스트 스택에서 foo함수의 실행컨텍스트 pop으로 제거
   * 전역코드도 더이상 실행할게 없으므로 종료,
   * 실행컨텍스트 스택에서 전역 실행컨텍스트 pop으로 제거

> \
> 💡 실행 컨텍스트 스텍은 이처럼, 코드 실행순서를 관리함, 실행 컨텍스트의 최상위에 있는 실행 컨텍스트는 언제나 현재 실행중인 코드의 실행컨텍스트이다 running execution context라고 부름 (실행중인 실행컨텍스트)\ <br>

## 23.5 렉시컬 환경

> 📌 스코프와 식별자를 관리
>
> 실행 컨텍스트 스택 - 실행 순서 관리\
> 렉시컬 환경 - 식별자와, 식별자에 바인딩 된 값, 상위스코프 참조 기록

### 렉시컬 환경 구성

* 렉시컬 환경은 객체 형태의 스코프를 생성

  * 키와 값을 갖는 객체형태의 스코프 생성

  * 식별자 키로 등록, 식별자에 바인딩 된 값 관리

  > 💡 스코프를 구분하여 식별자를 등록하고 저장소 역할을 한다\
  > 💡 렉시컬 스코프의 실체

<br>

* 실행 컨텍스트와 렉시컬 환경의 관계
  * 초기 컨텍스트 생성시 - 참고만 할것 ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_exical.jpeg) 동일한 렉시컬 환경을 참조하지만, 이후 몇가지 상황에서, 새로운 렉시컬 환경을 생성하고, 이후 상황에 따라 Variable, Lexical Environment 환경은 달라질 수 있다 stict mode, try/catch 같은 특수한 상황에서는 Variable Environment와 Lexical Environment 값이 달라질 수 있지만, 책에서는 둘을 구분 않고 Lexical Environment로 통합해서 간략하게 설명함!!\ <br>
* 렉시컬 환경은 두개의 컴포넌트로 구성된다\
  ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Lexical_Environment.png)

  | 컴포넌트 이름                                                      | 설명                                                                                                              |
  | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
  | <p>환경 레코드<br>(Environmental Record)</p>                      | <p>스코프에 포함된 식별자 등록,<br>식별자에 바인딩 된 값 관리,<br>소스코드 타입에 따라 관리하는 내용이 다르다</p>                                         |
  | <p>외부 렉시컬 환경 참조<br>(OuterLexicalEnvironmental Reference)</p> | <p><strong>상위 스코프를 가리킴</strong><br>해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경을 말한다<br>단방향 링크드 리스트인 스코프체인을 구현함</p> |
  | <p><br></p>                                                  |                                                                                                                 |
  | <p><br></p>                                                  |                                                                                                                 |

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

### 예제를 통해 실행 컨텍스트와 코드 실행 결과 관리 확인해보기

```javascript
var x = 1;
const y = 2;
function foo(a) {
  var x = 3;
  const y = 4;

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

### 23.6.1. 전역 객체 생성

* 전역 객체는 전역 코드가 평가되기 이전에 생성됨

  ```
    전역 객체 생성시 전역 객체에 추가되는 것들
    ✅ 빌트인 전역 프로퍼티
    ✅ 빌트일 전역 함수
    ✅ 표준 빌트인 객체 - (Object, Array, String, Number, Boolean, Map, Set ...)
    ✅ 호스트 객체 (클라이언트 - Web API)
  ```
* 전역 객체도 Object.prototypedmf 상속받는다
  * 전역 객체도 프로토 타입 체인의 일원이다

***

### 23.6.2 전역 코드 평가 🔥❗️

\##평가순서

* 소스코드가 로드 된 이후 자바스크립트 엔진은 다음과 같은 순서로 전역 코드를 평가한다

  ```
    🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥

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

    🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
  ```

  전역 실행 컨텍스트와 렉시컬 환경 생성 결과

  > ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_process.jpeg) ><br>

<br>

#### 🚩 평가 순서 세부내용

**1. 전역 실행 컨택스트 생성**

* 비어있는 실행 컨텍스트 생성, 실행 컨텍스트 스택에 푸시

**2. 전역 렉시컬 환경 생성**

* 전역 렉시컬 환경을 생성하고 실행 컨텍스트에 바인딩

***

#### **전역 렉시컬 환경 생성 세부내용**

**2-1. 전역 환경 레코드 생성 🔥❗️**

> 📌 전역 환경 레코드 = 객체 환경 레코드(var) + 선언적 환경 레코드(let, const)

* 전역 스코프(전역변수 관리), 전역 객체의 빌트인 프로퍼티, 빌트인 함수, 표준 빌트인 객체 제공
* ES6 이전에는 전역 객체가 전역 환경 레코드의 역할을 수행
* ❗️ 전역에서 선언된 let, const 키워드 사용 시 전역적인 프로퍼티가- 아니라 개념적인 블록에 존재하게 되는데..\
  이러한 관리를 위해 전역 환경 레코드는

  **객체 환경 레코드 + 선언적 환경 레코드**로 구성

  ```
  ✅ 기존의 var - 전역 프로퍼티 - "객체" 환경 레코드(Object Environment Record)
  ✅ const, let - 전역 블록에 존재 - "선언적" 환경 레코드(Declarative Environmental Record)
  ```

**2-1-1. 객체 환경 레코드 생성**

> 📌 객체 환경 레코드는 BindingObject와 연결, BindingObject는 var 또는 전역 환경에서 function 키워드들을 전역 객체(Window)에 연결

```
💡 var 키워드, 전역에서의 function이 전역 객체의 프로퍼티와 메서드가 되는 메커니즘
💡 전역 객체 식별자 없이 프로퍼티, 메서드 사용 가능한 이유( window.alert || alert )
```

**🔥🔥 예제 코드 체크**

```javascript
//전역 환경, 객체 환경 레코드 생성 중
  var x = 1;
  // const y = 2;

  function foo() ...
```

* var x
  * 생성과 초기화 동시에 진행, 변수 따라서 선언문 이전에도 참조 가능 (실행 이전에 평가가 일어나니까 - 호이스팅)
  * 생성시 BindingObject를 통해 전역 객체에 변수 식별자 등록, undefined으로 초기화
  * var 키워드로 선언한 함수 표현식도 동일하게 동작한다
* function foo()
  * 함수 선언문으로 선언한 함수는 - 함수 이름을 식별자로 BindingObject를 통해 전역 객체에 키로 등록
  * 키로 등록함과 동시에 생성된 함수 객체 즉시 할당 \* **변수 호이스팅 -> undefined 먼저 할당, 함수 선언문 -> 함수 객체 먼저 할당** - 변수 호이스팅과 함수호이스팅의 차이
* ✅ 객체 환경 레코드 생성결과

  ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Object_environmnetal_record.png)

**2-1-2. 선언적 환경 레코드 생성**

> 📌 let, const는 선언적 환경 레코드에 등록되고 관리된다 전역에서의 let, const는 전역 프로퍼티가 아니라 개념적인 블록 즉 전역의 선언적 환경 레코드 내에 존재

**🔥🔥 예제 코드 체크**

```javascript
  //전역 환경, 선언적 환경 레코드 생성중
    var x = 1;

    // const, let 키워드 -> 선언적 환경 레코드에서 생성
    const y = 2;

    function foo() ...
```

* const y
  * 전역 객체의 프로퍼티가 되지 않음, 따라서 window\.y로 접근 불가능
  * **생성과 초기화 분리**해서 진행 변수가 undefined로 초기화 되어있지 않으므로 참조시 에러 발생
    * 호이스팅은 발생하나, 실제로는 작동하지 않음, 초기화 전까지 일시적 사각 지대 (Temporal Dead Zone)
  * 생성시 BindingObject를 통해 전역 객체에 변수 식별자 등록, undefined으로 초기화
* 🔥 TDZ 관련 예제

  ```javascript
      let foo = 1; 전역 함수
      {
          console.log(foo);
          let foo = 2;
      }
  ```

  * let 키워드로 선언한 변수가 호이스팅 되지 않는다면?
    * 전역 변수를 참조해서, 1을 출력해야함
    * 하지만 let 변수도 호이스팅이 일어나기 때문에 참조에러가 발생
      * 블록 안의 console.log는 블록 안의 foo 참조
      * 블록 안의 foo가 현재 TDZ 상태이므로 참조 에러(RefereneError) 발생
* ```
  ✅ 객체 환경 레코드, 선언적 환경 레코드 생성결과
  ```

  ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Declarative_Environmental_record.png) 선언적 환경 레코드에 등록은 된 상태이지만, 값은 초기화 되지 않음

> 💡 객체 환경 레코드와 선언적 환경 레코드는 협력하여 스코프와 전역 객체를 관리

***

***

**2-2. This 바인딩**

* 전역 환경 레코드의 \[\[GlabalThisValue]] 내부 슬롯에 this가 바인딩,
  * 전역 코드에서 this는 일반적으로 전역 객체를 가리킴, 전역 환경 레코드의 \[\[GlobalThisValue]]에는 window객체가 바인딩된다.
* this 바인딩은 전역 환경 레코드와 함수 환경 레코드에만 존재함!!
  * this 바인딩은 전역환경 또는 함수환경에서만 가능
* ✅ 전역 환경 레코드 this 바인딩 결과 ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Global_this_binding.png)

2-3. 외부 렉시컬 환경에 대한 참조 결정

* 현재 평가중인 소스코드 포함, 외부 소스코드의 렉시컬 환경을 가리킴
  * 즉 상위 스코프를 가리킴, 단방향 링크드인 스코프 체인 구현
* 현재 평가 중인 소스코드는 전역코드임
  * 따라서 전역 렉시컬 환경 - 외부 렉시컬 환경은 null이 할당됨
    * **전역 렉시컬 환경이 스코프 체인의 종점에 존재한다**@@
* ✅ 전역 렉시컬 환경 - 외부 렉시컬 환경 참조 결정 결과 ![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Outer_Lexical_Environment_Reference.png)

***

### 23.6.3 전역 코드 실행

```javascript
   var x = 1;
   const y = 2;

function foo()
```

* 전역 렉시컬 환경 생성 이후 전역 코드가 생성된다
  * 변수 할당문 실행, x와 y에 값이 할당된다
  * foo 함수가 호출됨
* **🔥식별자 결정**
  * 변수 할당문, 함수 호출문 실행하기 전에 식별자를 먼저 결정해야 하는 어떤 방식으로 결정되는가?

    ```
    1. 실행중인 실행 컨텍스트에서 검색
    2. 없으면 상위스코프로 이동해서 식별자 검색
    ```
  * 현재 전역 실행 컨택스트 실행 중이므로, 전역 렉시컬 환경 안의 객체 환경 레코드, 선언적 환경 레코드 안에 x와 y foo가 모두 등록이 되어있다.
  * 만약 식별자가 없었다면, 전역에서의 상위 스코프는 null 이므로, 참조 에러를 발생시킨다

***

### **23.6.4. foo 함수 코드 평가🔥❗️**

* 예제 코드

```javascript
var x = 1;
const y = 2;
function foo(a) {
  var x = 3;
  const y = 4;

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

* x에 1 할당, y에 2 할당 이후 foo 함수를 실행하게 된다 이때 전역 코드의 실행을 일시 중지하고, foo 함수 내부로 코드의 제어권이 이동된다
* 함수 코드 평가는 아래 순서로 진행된다

  ```
    1. 함수 실행 컨텍스트 생성
    2. 함수 렉시컬 환경 생성
        2-1. 함수 환경 레코드 생성
        2-2. this qkdlseld
        2-3. 외부 렉시컬 환경에 대한 참조 결정
  ```

1. 함수 실행 컨텍스트 생성

* foo함수 실행 컨텍스트를 생성함
  * 함수 실행 컨텍스트는 함수 렉시컬 환경이 완성된 다음 실행 컨텍스트 스텍에 푸시된다
  * 이때 foo함수 실행 컨텍스트는 실행 컨택스트 스택의 최상위로 올라감, (실행중인 컨텍스트)

1. 함수 렉시컬 환경 생성

* foo함수 렉시컬 환경(Function Lexical Environment)을 생성하고, foo 함수 실행 컨텍스트에 바인딩한다
* 함수 렉시컬 환경은 함수 환경 레코드 + 외부 렉시컬 환경에 대한 참조로 구성됨!! (기본 렉시컬 환경 구성 = 환경 레코드 + 외부 렉시컬 환경 참조)

  2.1 함수 환경 레코드 생성

> 📌 함수 렉시컬 환경 - 함수 환경 레코드 생성할 때
>
> 매개변수, arguments 객체, 함수 내부의 지역변수와 중첩 함수 등록 및 관리

![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Function_Environment_Record.png)

* argumetns / foo 함수 내의 x, y, bar함수 / callee - 함수 환경 레코드에 등록

### **2.2 this 바인딩**

> 📌 this는 함수 호출 방식에 따라 결정된다. 함수 호출 시에 함수 렉시컬 환경 내의 \[\[ThisValue]]에 바인딩된다

![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Function_this_binding.png)

* 22장 this에 설명 되어있음
  * 요약
    1. 일반함수 - 전역 객체 바인딩
    2. 객체 메서드 - 메서드를 호출한 객체 바인딩
    3. 생성자 함수 - 미래의 인스턴스 바인딩
    4. apply,call,bind - 첫번째 인수로 전달해준 객체

### **2.3 외부 렉시컬 환경에 대한 참조 결정**

> 📌 지금 실행하는 함수 "정의"가 평가된 시점의 실행컨텍스트의 렉시컬 환경의 참조가 할당된다 함수의 외부 렉시컬 환경 참조 함수가 정의된 행 컨텍스트의 렉시컬 환경을 참조

* foo가 평가될 시점에서의 실행 컨텍스트는 전역 실행 컨텍스트이므로, 전역 렉시컬 환경을 참조함.
* 상위 스코프 결정 시 외부 렉시컬 참조를 활용한다
  * 함수 객체 생성 시 함수의 상위 스코프 (= 외부 렉시컬 환경 참조, =함수 정의가 평가된 실행 컨텍스트의 렉시컬 환경)를 함수 객체의 내부슬롯 \[\[Environment]]에 저장한다.

![img](https://github.com/Endless-Creation-32nd/javascript-deep-dive/blob/gitbook/23%EC%9E%A5-%EC%8B%A4%ED%96%89_%EC%BB%A8%ED%83%9D%EC%8A%A4%ED%8A%B8/img/context_Function_Outer_Lexical_Environment_Reference.png)

***

23.6.5. foo 함수 실행

* 런타임 시작, 매개변수에 할당, 변수 할당 등 지역변수에 값이 할당된다 bar 함수 호출됨
  * 식별자 결정을 할 때 함수 렉시컬 -> 외부 렉시컬 참조 순으로 식별자를 검색하고 값을 바인딩한다

    23.6.6\~7 bar 함수 코드 평가/실행

```javascript
var x = 1;
const y = 2;
function foo(a) {
  var x = 3;
  const y = 4;

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

* foo 함수를 평가 / 실행 한 것처럼 동일하게 동작
  * bar 함수 호출 시 내부 제어권 bar 함수로 이동
  * 함수 평가
    * bar) 함수 실행 컨텍스트 생성 - 함수 렉시컬 환경 생성 - 환경 레코드 등록 - this 바인딩 - 외부 렉시컬 환경 참조 순으로 평가
      * 외부 렉시컬 환경은, bar 함수 평가가 실행되는 foo 함수의 렉시컬 환경,,, 정의된 함수의 렉시컬 환경이라고 생각하면 될듯 하다
  * 함수 실행
    * z에 값 할당 이후 console.log 실행
* console.log 실행
  * console 식별자 스코프 체인에서 검색한다
    * 현재 실행중인 렉시컬 환경 ->외부 렉시컬 ->외부 렉시컬 반복해서 console 식별자를 찾는다
      * bar 렉시컬 없음 -> foo 렉시컬 없음 -> 전역 렉시컬 -> 객체 환경 레코드의 BindingObject에서 찾게 됨
  * log 메서드 검색
    * console 객체의 프로토타입 체인을 통해 메서드를 검색
  * 표현식 (a,b,x,y,z) 평가
    * 렉시컬 -> 렉시컬 계속 참조하면서 식별자 a,b,x,y,z 를 계속해서 찾는다
    * 찾은 이후 식을 평가하여 인수로 전달해준다.
  * log 메서드 호출
    * 표현식 평가 이후 생성된 값을 console.log에 전달하여 호출함

      23.6.8 bar 함수 코드 실행 종료
  * 실행 컨텍스트에서 bar 함수가 종료되어도 bar 함수의 렉시컬 환경은 즉시 소멸하지 않음
    * 실행 컨텍스트에 의해 참조되지만 렉시컬 환경은 독립적인 객체이므로, 누군가에 의해 참조되지 않을 때 가비지 컬렉터에 의해 소멸
  * bar 함수가 종료되어도, 누군가 bar 렉시컬 환경을 참조한다면 소멸되지 않는다

    23.6.9 foo 함수 코드 실행 종료 / 23.6.10 전역 코드 종료
* 각각의 함수는 실행이 종료되면서 실행 컨텍스트 스택에서 팝 되어 제거된다,
* 전역 코드 까지 종료되면 실행 컨텍스트 스택에는 아무것도 남지 않는다.

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

> 📌 if / for / while / try, catch 문에서는 블록 렉시컬 환경을 생성한다. 이때 생성된 블록 렉시컬 환경이 블록 레벨 스코프 메커니즘을 가능하게 한다

* 코드 블록이 실행 되었을 때, 블록 레벨 스코프 생성을 위해 렉시컬 환경 새롭게 생성
  * 선언적 환경 레코드를 갖는 렉시컬 환경이 생성된다.
  * 외부 참조 렉시컬 환경은 코드블록이 실행된 렉시컬 환경을 참조한다.
* 코드블록이 실행 될 때마다 렉시컬 환경을 생성
  * for문의 경우 매 반복마다 독립적인 렉시컬 환경을 생성, 식별자 값 유지
  * 24장 클로저에 내용이 많다.
* 코드블록 실행이 종료되면, 이전의 렉시컬 환경으로 돌아감
* var 변수는 함수 코드블록만 지역 스코프로 인정, let, const 변수는 모든 코드 불록 지역 스코프로 인정

\`
