내가 찾아가는 JavaScript_실행 컨텍스트(下)

Daniel Woo·2022년 4월 4일
0
post-thumbnail

소개

이전 글에서는 간단한 예제 코드를 보면서 실행 컨텍스트의 역할실행 컨텍스트 스택(call stack), 렉시컬 환경(Lexical environment)에 대해 알아보았다. 이번 글에서는 새로운 예제를 통해 실행 컨텍스트 생성 메커니즘, 실행 결과의 관리 그리고 식별자 검색의 과정등에 대해 다룰 것이다.

이전 글과 비슷한 맥락이지만 실행 컨텍스트 동작 원리를 더 깊게 봄으로써 JavaScript 언어가 어떻게 작동하는지에 대한 대략적인 그림을 그릴 수 있을 것이다.

만약 이전 글을 보지 못했다면 아래를 참고하세요 😉


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

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);
모던 JavaScript Deep Dive [예제 23-04]

전역 객체 생성

전역 객체는 전역 소스코드가 평가되기 전에 생성된다. 전역 객체가 생성되었다는 것은 그 이전에는 존재하지 않았다는 것이다. 하지만 이것이 그 전에 아무것도 존재하지 않은 것을 의미하지는 않는다.

setTimeout, alert 메소드 등 전역 객체가 다양한 메소드나 값을 사용한 경험을 떠올려보자. 이것은 전역 객체가 만들어지면서 JS의 내장 prototype이 상속되어 이미 존재하는 기능들을 유전자로 받았기 때문이다. 즉, 전역 객체가 생성되기 이전에도 기본으로 등록되어있는 prototype이 존재한다. 그것이 전역 객체가 생성되면서 상속되는 것이다.

전역 코드 평가

JS엔진은 코드를 바로 실행하지 않는다. 그 이전에 소스 코드에 명시되어 있는 식별자를 특정한 공간에 등록하는 과정인 코드 평가 단계를 거친다.

전역 실행 컨텍스트 생성

코드 평가가 끝나면 코드는 순차적으로 실행된다. 실행되고 있는 코드가 속해 있는 실행 컨텍스트는 우선 순위를 부여 받는다. 때문에 가장 처음에 실행되는 실행 컨텍스트는 가장 바깥에 존재하는 전역 실행컨텍스트일 것이다. 이 컨텍스트는 실행 컨텍스트의 실행 순서를 관리하는 자료구조인 call stack, 즉 실행 컨텍스트 스택에서 쌓이게 된다.

실행 컨텍스트 스택에서 실제로 실행되고 있는 컨텍스트를 실행 중인 실행 컨텍스트라고 한다. 실행 중인 실행 컨텍스트는 코드가 실행되면서 다른 실행 컨텍스트에게 실행 순서를 내어줄 수 있다. 즉, 실행 중인 실행 컨텍스트는 코드의 진행 규칙에 따라 달라질 수 있다.

전역 렉시컬 환경 생성

var x=1, const y=2, foo(a)처럼, 방금 전 코드 평가로 파악된 변수들은 렉시컬 환경에 식별자만 파악되어 key값으로 저장된다. 전역 렉시컬 환경은 렉시컬 환경 내부에서 생성되는 것은 아니며, 외부에서 생성되지만 렉시컬 환경에 바인딩되어 참조할 수 있게 된다.

한편, 전역 렉시컬 환경은 환경 레코드(environment record)외부 렉시컬 환경 참조(OuterLexicalEnvironmentRefference)두 가지로 이루어져 있다. 다시, 환경 레코드는 객체 환경 레코드와, 선언적 환경 레코드로 나뉜다. 연쇄적으로 나뉘어진 자료구조라 복잡하지만 각 자료구조가 어떠한 역할을 담당하고 있는지만 파악할 수 있다면 거의 성공한 거다!

객체 환경 레코드에는 var키워드로 선언된 식별자가 관리된다. 이 식별자는 전역 객체에서 새로운 프로퍼티처럼 사용할 수 있다. 선언적 환경 레코드에는 let과 const 예약어로 선언된 변수의 식별자가 다루어지는 곳이다. 이 둘의 차이는 우리가 아는 호이스팅 현상이 일어나는 이유이다.

예약어 var는 선언과 초기화 간계가 동시에 이루어지지만, let과 const는 선언 단계와 초기화 단계가 분리되어 있어 코드가 실행(런타임)되기 전에 값을 초기화하지 못하고 오류를 반환한다. 즉, var, let, const 모두가 호이스팅이 일어나지만 let,과 const의 경우는 값 초기화를 하지 못하기 때문에 변수의 초기화로 가는 과정인 TDZ에서 발이 묶이고, 초기화 되지 못한 변수는 런타임 에러를 발생시키는 것이다.

this 바인딩

this 바인딩인 전역 환경 레코드와 함수 환경 레코드에만 존재한다. 기본적으로 전역 객체를 this에 바인딩 하며, 전역 환경 레코드의 this는 전역 객체가 참조된다.

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

외부 렉시컬 환경에 대한 참조(OuterLexicalEnvironmentReference)는 상위 스코프를 가리킨다. 스코프를 통해 현재 실행 중인 컨텍스트의 외부 소스 코드를 포함하는 스코프 체인을 만든다.

스코프: 어디에서 정의했는지에 따라 결정
this: 어디에서 호출했는지에 따라 결정

전역 코드 실행

식별자 결정: 식별자 결정을 위해 식별자를 검색할 때는 실행 중인 실행 컨텍스트에서 식별자를 검색하기 시작한다.

실행 중인 실행 컨텍스트의 렉시컬 환경에서 코드의 식별자를 검색할 수 없는 경우 그의 상위에 해당하는 실행 컨텍스트의 렉시컬 환경에서 찾는다. 이러한 과정은 최상단의 실행 컨텍스까지 이루어진 후, 값을 참조할 수 없을 때 참조 에러(Refference Error)를 발생된다.

실행 컨텍스트: 소스코드가 실행되는 환경과 참조에 필요한 값을 등록하여 관리하는 공간

profile
모두가행복한세상을만들고싶은사람

0개의 댓글