JavaScript 프로그램 평가와 실행 과정(1)

Beautify.log·2021년 10월 31일
0
post-thumbnail

JavaScript(자바스크립트)의 내부 구조에 대해 알아봅시다.

실행 가능한 코드

자바스크립트 엔진은 실행 가능한 코드를 만났을 때 그 코드를 평가합니다.
실행 가능한 코드일 때 실행 문맥(Execution Context)으로 만들게 되는데 이러한 코드의 유형은 이렇습니다.

  1. 전역코드(Global Code) : 전역 객체 Windows 아래에 정의된 함수
  2. 함수코드(Function Code)
  3. eval 코드 : eval 함수

실행 문맥(Execution Context)의 구성

실행문맥은 실행 가능한 코드가 실행되고 관리되는 영역입니다. 실행에 필요한 모든 정보를 컴포넌트 여러개가 나누어서 관리하도록 만들어져 있습니다.

  1. 렉시컬 환경 컴포넌트(Lexical Environment Component)
  2. 변수 환경 컴포넌트(Variable Environment Component)
  3. 디스 바인딩 컴포넌트(This Binding Component)

렉시컬 환경 컴포넌트의 구성

자바스크립트 엔진이 자바스크립트 코드를 실행하기 위한 자원을 모아두는 곳입니다. 함수 또는 블록 유효범위 안에 있는 식별자와 결과값이 저장됩니다. 자바스크립트 엔진은 해당 자바스크립트 코드의 유효범위 안에 있는 식별자와 그 식별자가 가리키는 값을 키와 값(key and value)의 쌍으로 묶어서 렉시컬 환경 컴포넌트에 기록합니다.

이는 렉시컬 환경 타입의 컴포넌트이고 변수 환경 컴포넌트도 또한 이에 속합니다. 두개의 컴포넌트는 서로 type이 같고 with문을 사용할 때를 제외하면 내부 값이 같아 똑같이 취급하면 좋을 것 같습니다.

// 렉시컬 환경 컴포넌트
LexicalEnvironment: {
  // 환경 레코드
  EnvironmentRecord: {
    ...
  },
  // 외부 렉시컬 환경 참조
  OuterLexicalEnviormentReference: {
    ...
  }
}

렉시컬 환경 컴포넌트는 환경 레코드와 외부 렉시컬 환경 참조 컴포넌트로 구성되는데, 환경 레코드는 유효 범위 안에 포함된 식별자를 기록하고 실행합니다. 자바스크립트 엔진은 유효 범위 안의 식별자와 결과값을 묶어서 환경 레코드에 기록합니다.

자바스크립트는 함수 안에 함수를 중첩할 수 있는 기능이 있습니다. 따라서 자바스크립트 엔진은 유효 범위 이외의 유효범위도 검색할 수 있어야 하는데, 이때 외부 렉시컬 환경 참조에는 함수를 둘러싸고 있는 코드가 속한 렉시컬 환경 컴포넌트의 참조가 저장됩니다.
중첩된 함수 안에서 바깥 코드에 정의된 변수를 읽거나 써야할 때, 자바스크립트 엔진은 외부 렉시컬 환경 참조를 따라 한단계씩 렉시컬 환경을 거슬러 올라가서 그 변수를 검색하게 됩니다.

환경 레코드의 구성

환경 레코드는 렉시컬 환경 컴포넌트의 구성요소이고 렉시컬 환경 안의 식별자와 그 식별자가 가리키는 값의 묶음이 저장되는 영역입니다. 이 환경 레코드는

  1. 선언적 환경 레코드(Declarative Environment Record)와
  2. 객체 환경 레코드(Object Environment Record)

로 구성됩니다.

// 환경레코드
EnvironmentRecord: {
  // 선언적 환경 레코드
  DeclarativeEnvironmentRecord: {
    ...
  },
  // 객체 환경 레코드
  ObjectEnvironmentRecord: {
    ...
  }
}

선언적 환경 레코드

선언적 환경 레코드에는 함수와 변수, catch 문의 식별자와 실행 결과가 저장됩니다.

객체 환경 레코드

객체 환경 레코드는 실행 문맥 외부에 별도로 저장된 객체의 참조에서 데이터를 읽거나 씁니다. 선언적 환경 레코드는 식별자와 실행결과를 key-value 형태로 관리한다는 점에서 차이가 있습니다.
예를들어 with문의 렉시컬 환경이나 전역 객체처럼 별도의 객체에 저장된 데이터는 그 객체가 가진 키와 값의 쌍을 복사해 오는 것이 아니라 그 객체 전체의 참조를 가져와서 객체 환경 레코드의 bindObject라는 프로퍼티에 묶도록 만들어져 있습니다.

전역 환경과 전역 객체의 생성

자바스크립트 인터프리터(번역기(?))는 시작하자마자 렉시컬 환경 타입의 전역환경을 생성합니다. 자바스크립트의 인터프리터는 브라우저에 내장되어 있으며 새로운 페이지를 읽어 들인 후에 전역 객체를 생성해줍니다. 그리고 전역 객체를 생성한 다음 전역 환경의 객체 환경 레코드에 전역 객체의 참조를 대입합니다.

전역객체는 다음과 같습니다.

분류프로퍼티
전역프로퍼티undefined, NaN, Infinity
생성자Object(), String(), Number()
전역함수parseInt(), parseFloat(), isNaN()
내장 객체Math, JSON, Reflect

위에서 언급한 상태를 의사 코드로 표현해 보면,

// 전역환경
GlobalEnvironment = {
  ObjectEnvironmentRecord: {
    bindObject: window
  },
  OuterLexicalEnvironmentReference: null
}
// 전역 실행 문맥
ExecutionContext = {
  LexicalEnvironment: GlobalEnvironment,
  ThisBinding: window,
}

웹 브라우저의 자바스크립트 실행 환경에서는 Window 객체가 전역 객체가 되므로 객체 환경 레코드의 bindObject 프로퍼티에는 전역 객체 Window의 참조가 할당되게 됩니다. 이로 인해 전역 환경의 변수와 함수를 Window 안에서 검색합니다.
또한 전역환경 외부에는 별다른 렉시컬 환경이 없으므로 외부 렉시컬 환경 참조에는 null을 할당하게 됩니다.
그리고 전역 실행 문맥의 ThisBinding 컴포넌트에도 Window의 참조가 할당되어 전역 실행 문맥의 thisWindow를 가리키게 되고 전역 실행 문맥의 property를 ThisBinding 컴포넌트 안에서 검색하게 됩니다.

다음 포스팅에서는 프로그램의 실행과 관련하여 평가, 전역변수, 실행문맥 등에 대해 살펴보겠습니다.

출처

이소 히로시, 모던 자바스크립트 입문(길벗), 271-275.

profile
tried ? drinkCoffee : keepGoing;

0개의 댓글