한준호

[Modern javascript] 실행 컨텍스트(2) 본문

Frontend/modern javascript

[Modern javascript] 실행 컨텍스트(2)

igoman2 2021. 8. 28. 22:26
728x90
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);

 

- 위 코드의 실행 컨텍스트에 대한 진행 과정을 정리한 그림이다.

■ 전역 객체 생성

- 전역 객체는 전역 코드가 평가되기 이전에 생성된다.

- 전역 객체도 Object.prototype을 상속받는다.

 

■ 전역 코드 평가

- 소스코드가 로드되면 자바스크립트 엔진은 전역 코드를 평가하고 다음과 같은 순서를 가진다.

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

1. 전역 실행 컨텍스트 생성

- 전역 실행 컨텍스트를 생성하여 실행 컨텍스트 스택에 푸시

 

2. 전역 렉시컬 환경 생성

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

- 전역 렉시컬 환경은 환경 레코드와 외부 렉시컬 환경에 대한 참조로 구성된다.

 

2.1 전역 환경 레코드 생성

- 객체 환경 레코드(var), 선언적 환경 레코드(let, const)로 구성된다.

 

2.1.1 객체 환경 레코드 생성

- 전역 코드 평가 과정에서 var 키워드로 선언한 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 환경 레코드의 객체 환경 레코드에 연결된 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 된다.

- 함수 선언문으로 정의된 함수는 BindingObject를 통해 전역 객체에 키로 등록하고 생성된 함수 객체를 즉시 할당하지만 var로 선언된 변수는 undefined를 할당한다.

 

2.1.2 선언적 환경 레코드 생성

- 함수 호이스팅이 발생하는 것은 맞지만 선언 단계와 초기화 단계까 분리되어 진행되므로 일시적 사각지대가 존재한다.

 

2.2 this 바인딩

- 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 this가 바인딩된다. 일반적으로 전역 환경 레코드엔 전역 객체가 바인딩된다.

- 전역 환경 레코드를 구성하는 객체 환경 레코드와 선언적 환경 레코드엔 this 바인딩이 없다

 

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

- 상위 스코프를 가리킨다.

 

 

■ 전역 코드 실행

전역 코드가 실행되면 변수 할당문이 실행되어 전역 변수 x, y에 값이 할당되고 foo함수가 호출된다.

-> foo함수를 호출하는 코드에 도달하면 해당하는 식별자가 스코프 내에 존재하는지 찾는다.

-> 식별자 결정을 위해 식별자를 검색할 때는 실행중인 컨텍스트에서 식별자를 검색한다.

-> 현재 실행 컨텍스트는 전역 실행 컨텍스트이므로 전역 렉시컬 환경에서  식별자 x, y, foo를 검색한다.

-> 실행 컨텍스트 렉시컬 환경에서 식별자를 검색할 수 없으면 외부 렉시컬 환경 참조가 가리키는 렉시컬 환경, 즉 상위 스코프로 이동하여 식별자를 검색한다.

 

■ foo 함수 코드 평가

- 함수 코드 평가는 다음과 같은 순서를 가진다.

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

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

- foo함수 실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시되어 실행 컨텍스트가 된다.

 

2. 함수 렉시컬 환경 생성

- foo 함수 렉시컬 환경을 생성하고 foo 함수 실행 컨텍스트에 바인딩한다.

 

2.1 함수 환경 레코드 생성

- 함수 환경 레코드는 매개변수, arguments 객체, 함수 내부의 지역 변수와 중첩 함수를 등록하고 관리한다.

 

2.2 this 바인딩

- 함수 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 this가 바인딩된다.

- foo 함수는 일반 함수로 호출되었으므로 this는 전역 객체를 가리킨다.

- 함수 환경 레코드의 [[ThisValue]] 내부 슬롯에는 전역 객체가 바인딩 되고, 따라서 foo 함수 내에서 this를 참조하면 [[ThisValue]] 내부 슬롯에 바인딩되어 있는 객체가 반환된다.

 

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

- foo 함수는 전역 코드에 정의된 함수이므로 외부 렉시컬 환경 참조에는 전역 렉시컬 환경이 할당된다.

- 자바스크립트는 함수를 어디서 호출했는지가 아니라 어디서 정의했는지에 따라 상위 스코프를 결정한다.

- 함수의 상위 스코프를 함수 객체 내부 슬롯 [[Environment]]에 저장한다. 즉 함수 객체의 내부 슬롯 [[Environment]]가 렉시컬 스코프를 구성하는 메커니즘이다.

 

■ foo 함수 코드 실행

- 식별자 결정을 위해 실행 중인 컨텍스트의 렉시컬 환경에서 식별자를 검색한다.

-> foo 함수 렉시컬 환경에서 식별자 x, y를 검색한다.

 

■ bar 함수 코드 평가

- foo 와 동일하게 작동

 

■ bar 함수 코드 실행

- console 식별자를 스코프 체인에서 찾는다(bar -> foo -> 전역). 전역 렉시컬 환경의 전역 객체에서 찾을 수 있다.

- log 메서드를 console 객체에서 프로토타입 체인을 통해 검색한다

- a는 foo, b는 bar, x와 y는 foo, z는 bar 함수 렉시컬 환경에서 검색된다.

 

■ bar 함수 코드 실행 종료 -> foo 함수 코드 실행 종료 -> 전역 코드 실행 종료

- 실행 컨텍스트 스택에서 차례대로 제거되는데, 함수 렉시컬 환경까지 즉시 소멸하는 것은 아니다. 객체를 포함한 모든 값은 누군가에 의해 참조되지 않을 때 비로소 가비지 컬렉터에 의해 메모리 공간의 확보가 해제되어 소멸한다. 즉 bar 함수 실행 컨텍스트가 소멸되었다고 해도 누군가 bar 함수 렉시컬 환경을 참조하고 있다면 bar 함수 렉시컬 환경은 소멸하지 않는다.

 

 

◎var 키워드는 함수 레벨 스코프를 가지는 반면 let, const 키워드는 블록 레벨 스코프를 가진다고 했다. 개념적인 블록 내에 존재하는 것인데 그 블록이 바로 선언적 환경 레코드이다.

728x90

'Frontend > modern javascript' 카테고리의 다른 글

[Modern javascript] 클래스(1)  (0) 2021.08.31
[Modern javascript] 클로저  (0) 2021.08.31
[Modern javascript] 실행 컨텍스트(1)  (1) 2021.08.28
[Modern javascript] this  (0) 2021.08.26
[Modern javascript] 빌트인 객체  (0) 2021.08.26
Comments