개발 관련 도서

모던 자바스크립트 - 실행 컨텍스트(2)

mrban 2024. 5. 28. 00:57

실행 컨텍스트(1)에서 익힌 개념들을 가지고 구체적으로 예시를 통해 실행 컨텍스트가 어떻게 구현되는지 살펴보자

 

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. 전역 객체가 생성된다. 우리가 알고 있는 window 객체가 생성된다.

 

이후에 나올 과정부터는 특정 실행 컨텍스트 동작 원리의 반복이다. 아래 과정을 명심하고 넘어가자.

1. 실행 컨텍스트 생성

2. 함수 렉시컬 환경 생성

2-1. 함수 환경 레코드 생성

2-2. this 바인딩

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

 

 

 

2. 전역 코드 평가

  • 전역 실행 컨텍스트 생성: 실행 컨택스트 스택에 전역 실행 컨택스트를 푸시한다.

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

  • 전역 환경 레코드 생성: 객체 환경 레코드와 선언적 환경 레코드로 구분된다.
    • 객체 환경 레코드 생성: 전역 코드 평가 과정에서 var 키워드로 선언한 전역변수와 전역 함수는 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 된다. 이것이 var 키워드로 선언된 전역 변수와 전역 함수가 전역 객체의 프로퍼티와 메서드가 되는 원리이다.
      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);
      }
      자세히 보면 x에 undefined로 초기화되기 떄문에 우리가 변수 호이스팅이 발생하는 원인을 발견할 수 있다. 
  • 선언적 환경 레코드 생성:  let, const로 생성한 전역 변수는 선언적 환경 레코드에 등록되고 관리된다. 즉, 전역 객체의 프로퍼티가 되지 않는 다는 것이다. 그리고 const로 선언한 변수는 undefined로 초기화 되지 않기 때문에 일시적 사각지대에 빠지게 된다. 이처럼 변수 호이스팅은 발생하지만(y가 메모리에 존재하지만) 값을 참고할 수 없는 상태일 뿐이라는 것을 확인이 가능하다. 
  • this 바인딩

글로벌 환경 레코드에 this 가 바인딩되어 있다.

  • 외부 렉시컬 환경에 대한 참조 결정 : 상위 스코프를 가리킨다. 현재 평가중인 전역 실행 컨텍스트는 상위 스코프가 없기 때문에 null이 들어간다.

3. 전역 코드 실행

변수 x, y에 값이 할당된다. 그리고 foo함수가 호출되기 시작한다.

다른 스코프에 동일한 이름의 식별자가 여러개 존재할 수 있기 때문에 어느 스코프의 식별자를 참조하면 될지 결정할 필요가 있는데 이를 식별자 결정이라고 한다.

식별자 결정을 위해 식별자를 검색할 때는 실행중인 실행 컨텍스트에서 식별자를 검색하기 시작한다. 렉시컬 환경의 환경 레코드에 없다면 상위 스코프로 이동하여 식별자를 검색한다. 바로 이게 스코프 체인의 동작 원리이다.

 

4. foo 함수 코드 평가

이제 설명은 생략하고 그림으로만 대체하겠다. 위 과정과 똑같은 과정이 반복되는 것이다.

위 그림을 보면 함수 환경 레코드는 매개변수(a), arguments 객체, 지역변수, 중첩함수를 등록하고 관리한다.

 

 foo함수가 일반함수이므로 this는 전역객체를 가리킨다.

 

 

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

 

5. foo 함수 코드 실행

만약 실행중인 실행 컨텍스트의 렉시컬 환경에서 식별자를 검색할 수 없드면 외부 렉시컬 환경에 대한 참조가 가리키는 렉시컬 환경으로 이동하여 식별자를 검색한다.

 

6. bar 함수 코드 평가

7. bar 함수 코드 실행

그리고 console.log(a + b + x + y + z); 가 실행된다.

console은 스코프 체인을 타고 타고 내려가서 전역 렉시컬 환경의 Binding Object를 통해서 전역 객체에서 발견이 가능하다.

표현식 a + b + x + y + z 도 마찬가지로 스코프 체인을 통해서 검색하여 값을 찾아온다.

 

8. bar 함수 코드 실행 종료

스택에서 bar 실행 컨텍스트가 제거된다.

9. foo 함수 코드 실행 종료

스택에서 foo 실행 컨텍스트가 제거된다.

10. 전역 코드 실행 종료

스택에서 전역 실행 컨텍스트가 제거된다.

 

----

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

let, const로 선언한 변수는 블록 레벨 스코프를 따른다.

let x = 1;

if(true) {
	let x = 10;
    console.log(x); // 10
}

console.log(x);