diff --git "a/docs/23_\354\213\244\355\226\211 \354\273\250\355\205\215\354\212\244\355\212\270/\352\271\200\352\262\275\354\243\274.md" "b/docs/23_\354\213\244\355\226\211 \354\273\250\355\205\215\354\212\244\355\212\270/\352\271\200\352\262\275\354\243\274.md" index bf1d743f..b3faa15d 100644 --- "a/docs/23_\354\213\244\355\226\211 \354\273\250\355\205\215\354\212\244\355\212\270/\352\271\200\352\262\275\354\243\274.md" +++ "b/docs/23_\354\213\244\355\226\211 \354\273\250\355\205\215\354\212\244\355\212\270/\352\271\200\352\262\275\354\243\274.md" @@ -65,3 +65,107 @@ x = 1; 변수 선언문 `var x;`는 소스코드 평가 과정에서 이미 실행 완료되었기 때문에 소스코드 실행 과정에서는 변수할당문 `x = 1;`만 실행된다. 이때 `x` 변수에 값을 할당하려면 먼저 `x` 변수가 선언된 변수인지 확인해야 한다.
`x` 변수가 선언된 변수라면 값을 할당하고 할당 결과를 실행 컨텍스트에 등록해 관리한다. + +
+ +### 23.3 실행 컨텍스트의 역할 + +--- + +```js +// 전역 변수 선언 +const x = 1; +const y = 2; + +// 함수 정의 +function foo(a) { + // 지역 변수 선언 + const x = 10; + const y = 20; + + // 메서드 호출 + console.log(a + x + y); // 130 +} + +// 함수 호출 +foo(100); + +// 메서드 호출 +console.log(x + y); // 3 +``` + +##### 1. 전역 코드 평가 + +전역 코드를 실행하기 전에 전역 코드 평가 과정을 거치며 선언문만 먼저 실행한다. 따라서 전역 코드의 변수 선언문과 함수 선언문이 먼저 실행되고, 그 결과 생성된 전역 변수와 전역 함수가 실행 컨텍스트가 관리하는 전역 스코프에 등록된다. 이때 `var` 키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 프로퍼티와 메서드가 된다. + +##### 2. 전역 코드 실행 + +전역 코드 평가가 끝나면 런타임이 시작되어 전역 코드가 순차적으로 실행된다. 이때 전역 변수에 값이 할당되고 함수가 호출된다. 함수가 호출되면 전역 코드의 실행을 일시 중단하고 코드 실행 순서를 변경하여 함수 내부로 진입한다. + +##### 3. 함수 코드 평가 + +함수 내부로 진입하면 함수 내부의 문들을 실행하기에 전에 함수 코드 평가 과정을 거치며 함수 코드를 실행하기 위한 준비를 한다. 이때 매개변수와 지역 변수 선언문이 먼저 실행되고, 그 결과 생성된 매개변수와 지역 변수가 실행 컨텍스트가 관리하는 지역 스코프에 등록된다. 또한 함수 내부에서 지역 변수처럼 사용할 수 있는 `arguments` 객체가 생성되어 지역 스코프에 등록되고 `this` 바인딩도 결정된다. + +##### 4. 함수 코드 실행 + +함수 코드 평가 과정이 끝나면 런타임이 시작되어 함수 코드가 순차적으로 실행된다. **코드가 실행되려면 다음과 같이 스코프, 식별자, 코드 실행 순서 등의 관리가 필요**하다. + +1. 선언에 의해 생성된 모든 식별자(변수, 함수, 클래스)의 스코프를 구분하여 등록하고 상태 변화(식별자에 바인딩된 값의 변화)를 지속적으로 관리할 수 있어야 한다. +2. 스코프는 중첩 관계에 의해 스코프를 형성해야 한다. +3. 현재 실행 중인 코드의 실행 순서를 변경할 수 있어햐 하며 다시 돌아갈 수도 있어야 한다. + +이 모든 것을 관리하는 것이 **실행 컨텍스트**다. **실행 컨텍스트는 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역**이다. +구체적으로 말해, 실행 컨텍스트는 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 메커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다. + +
+ +### 23.4 실행 컨텍스트 스택 + +```js +const x = 1; +function foo() { + const y = 2; + + function bar() { + const z = 3; + console.log(x + y + z); + } + bar(); +} + +foo(); // 6 +``` + +##### 1. 전역 코드의 평가와 실행 + +자바스크립트 엔진은 먼저 저역 코드를 평가하여 전역 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시한다. 이때 전역변수 `x`와 전역 함수 `foo`는 전역 실행 컨텍스트에 등록된다. 이후 전역 코드가 실행되기 시작하여 전역 변수 `x`에 값이 할당되고 전역 함수 `foo`가 호출된다. + +##### 2. foo 함수 코드의 평가와 실행 + +전역 함수 `foo`가 호출되면 전역 코드의 실행은 일시 중단되고 코드의 제어권이 `foo` 함수 내부로 이동한다. 자바스크립트 엔진은 `foo` 함수 내부의 함수 코드를 평가하여 `foo` 함수 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시한다. 지역 변수 `y`와 중첩 함수 `bar`가 `foo` 함수 실행 컨텍스트에 등록된 후 코드가 실행되기 시작하여 지역 변수 `y`에 값이 할당되고 중첩 함수 `bar`가 호출된다. + +##### 3. bar 함수 코드의 평가와 실행 + +중첩함수 `bar`가 호출되면 코드의 제어권이 `bar` 함수 내부로 이동한다. `bar` 함수의 지역 변수 `z`가 `bar` 함수 실행 컨텍스트에 등록된 후 함수 코드가 실행되어 지역 변수 `z`에 값이 할당되고 `console.log` 메서드를 호출한 이후 `bar` 함수는 종료된다. + +##### 4. foo 함수 코드로 복귀 + +`bar` 함수가 종료되면 코드의 제어권은 다시 `foo` 함수로 이동한다. 이때 `bar` 함수 실행 컨텍스트를 실행한 컨텍스트를 스택에서 팝 하여 제거한다. 그리고 더 이상 실행할 코드가 없으므로 종료된다. + +##### 5. 전역 코드로 복귀 + +`foo` 함수가 종료되면 코드의 제어권은 다시 전역 코드로 이동한다. 이때 `foo` 함수 실행 컨테스트를 실행 컨텍스트 스택에서 팝하여 제거한다. 그리고 더 이상 실행할 전역 코드가 없으므로 전역 실행 컨텍스트도 실행 컨텍스트 스택에서 팝 되어 아무것도 남아있지 않게 된다. + +이처럼 **실행 컨텍스트 스택은 코드의 실행 순서를 관리**한다. 실행 컨텍스트 스택의 최상위에 존재하는 **실행 컨텍스트는 언제나 현재 실행 중인 코드의 실행 컨텍스트**다. + +
+ +### 23.5 렉시컬 환경 + +식별자와 식별자에 바인딩 된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트다. +렉시컬 환경은 키와 값을 갖는 객체 형태의 스코프를 생성하여 식별자를 키로 등록하고 식별자에 바인딩 된 값을 관리한다.
+실행 컨텍스트는 `LexicalEnvironment` 컴포넌트와 `VariableEnvironment` 컴포넌트로 구성된다.
+렉시컬 환경은 다음과 같이 두 개의 컴포넌트로 구분된다. + +1. 환경레코드(`Environment Record`): 스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩 된 값을 관리하는 저장소다. +2. 외부 렉시컬 환경에 대한 참조(`Outer Lexical Environment Record`): 외부 렉시컬 환경에 대한 참조는 상위 스코프를 가리킨다. 이때 상위 스코프란 외부 렉시컬 환경, 즉 해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경을 말한다.