꾸준한 개발일기

Javascript:: 실행 컨텍스트(2) 본문

JS/JavaScript

Javascript:: 실행 컨텍스트(2)

꾸개일 2022. 10. 22. 20:48
반응형
실행 컨텍스트 전체 구조

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

전역 객체 생성

예제5) 전역 객체는 프로토타입 체인의 일원

// Object.prototype.toString
window.toString(); // '[object Window]'

window.__proto__.__proto__.__proto__.__proto__ === Object.prototype; // true

전역 코드 평가

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

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


2. 전역 렉시컬 환경 생성

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


2.1 전역 환경 레코드 생성

  • 전역 환경 레코드의 객체 환경 레코드선언적 환경 레코드는 서로 협력하여 전역 스코프와 전역 객체(전역 변수의 전역 객체 프로퍼티화)를 관리


2.1.1. 객체 환경 레코드 생성
예제6)

var  x = 1;
const y = 2;

function foo(a) {
	...
}
  • 전역 변수 x와 전역 함수 foo는 객체 환경 레코드를 통해 객체 환경 레코드의 BindingObject에 바인딩되어 있는 전역 객체의 프로퍼티와 메서드가 됨



2.1.2. 선언적 환경 레코드 생성

  • var 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수이외의 선언(let, const 키워드로 선언한 전역 변수)는 선언적 환경 레코드에 등록되고 관리
  • 예제6)의 전역 변수 y는 let, const 키워드로 선언한 변수이므로 전역 객체의 프로퍼티가 되지 않기 때문에 window.y와 같이 전역 객체의 프로퍼티로서 참조할 수 없음

let foo = 1; // 전역변수

{ 
	// let, const 키워드로 선언한 변수가 호이스팅되지 않는다면 전역 변수를 참조해야 함
    // 하지만 let 키워드로 선언한 변수도 여전히 호이스팅이 발생하기 때문에
    // 참조 에러()가 발생
	console.log(foo); // Uncaught ReferenceError: Cannot access 'foo' before initialization
    let foo = 2; // 지역 변수
}


2.2 this 바인딩

  • 전역코드에서 this는 전역 객체를 가리키므로 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에는 전역 객체가 바인딩됨


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

  • 외부 렉시컬 환경에 대한 참조: 현재 평가 중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경(상위스코프)를 가리킴

전역 코드 실행

  • 변수 할당문이 실행되어 전역 변수 x, y에 값이 할당되고 foo 함수가 호출

식별자 결정

  • 어느 스코프의 식별자를 참조하면 되는지 결정하는 것
  • 식별자 결정을 위해 식별자를 검색할 때는 실행 중인 실행 컨텍스트에서 식별자를 검색하기 시작함

foo 함수 코드 평가

예제8) foo 함수를 호출하기 직전

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); // 호출 직전
  • foo 함수가 호출되면 전역 코드의 실행을 일시 중단하고 foo 함수 내부로 코드의 제어권이 이동하고 함수 코드를 평가하기 시작함



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

  • foo 함수 실행 컨텍스트를 생성함


2. 함수 렉시컬 환경 생성

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


2.1 함수 환경 레코드 생성
함수 환경 레코드

  • 함수 렉시컬 환경을 구성하는 컴포넌트
  • 매겨변수, argument 객체, 함수 내부에서 선언한 지역 변수와 중첩함수를 등록하고 관리


2.2 this 바인딩

  • 함수 환경 레코드의 [[ThisValue]] 내부 슬롯에 this(전역객체)가 바인딩


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

  • 외부 렉시컬 환경에 대한 참조에 foo 함수 정의가 평가된 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 할당됨

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

foo 함수코드 실행

  • 매개변수에 인수가 할당되고, 변수 할당문이 실행되어 지역 변수 x, y에 값이 할당되고, 함수 bar가 호출됨

bar 함수 코드 평가

예제9) bar 함수를 호출하기 직전

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);
  • foo 함수 코드 평가를 통해 foo 함수 실행 컨텍스트가 생성되었고 foo 함수 코드를 실행하고 있음

  • bar 함수가 호출되면 bar 함수 내부로 코드의 제어권이 이동하고 bar 함수 코드를 평가하기 시작함

bar 함수 코드 실행

  • 매개변수에 인수가 할당되고, 변수 할당문이 실행되어 지역 변수 z에 값이 할당됨

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

  1. console 식별자 검색
  2. log 메서드 검색
  3. 표현식 a + b + x + y + z의 평가
  4. console.log 메서드 호출

bar 함수 코드 실행 종료

  • console.log 메서드가 호출되고 종료하면 더는 실행할 코드가 없으므로 bar 함수 코드의 실행이 종료됨
  • 실행 컨텍스트 스택에서 bar 함수 실행 컨텍스트가 팝되어 제거되고 foo 실행 컨텍스트가 실행 중인 실행 컨텍스트가 됨

foo 함수 코드 실행 종료

  • 더 이상 실행할 코드가 없으므로 foo 함수 코드의 실행이 종료됨

전역 코드 실행 종료

  • 더 이상 실행할 코드가 없으므로 전역 코드의 실행이 종료됨

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

  • var 변수: 함수 코드 블록만 지역 스코프로 인정하는 함수 레벨 스코프
  • let, const 변수: 모든 코드 블록(함수, if문, for 문, while 문, try/catch 문 등)을 지역 스코프로 인정하는 블록 레벨 스코프임


예제11)

let x = 1;

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

console.log(x); // 1
  • if 문의 코드 블록이 실행되면 if 문의 코드 블록을 위한 블록 레벨 스코프를 생성해야 함
  • 선언적 환경 레코드를 갖는 렉시컬 환경을 새롭게 생성하여 기존의 전역 렉시컬 환경을 교체함
  • 새롭게 생성된 if 문의 코드 블록을 위한 렉시컬 환경의 외부 렉시컬 환경에 대한 참조는 if 문이 실행되기 이전의 전역 렉시컬 환경을 가리킴

  • for 문의 변수 선언문에 let 키워드를 사용한 for 문은 코드 블록이 반복해서 실행될 때마다 코드 블록을 위한 새로운 렉시컬 환경을 생성
  • for 문의 코드 블록 내에서 정의된 함수가 있다면 이 함수의 상위 스코프는 for 문의 코드 블록이 생성한 렉시컬 환경임





참고자료

  • 모던 자바스크립트 Deep Dive: 자바스크립트의 기본개념과 동작 원리





반응형
Comments