총 3가지 단계(part1 - 1단계 & part2 - 2, 3 단계)로 구성된 예시 코드들을 살펴보며 소스코드의 평가와 실행을 순차적으로 진행하는 인터프티러 언어인 자바스크립트의 엔진이 식별자(변수, 함수, 클래스 등의 이름)를 어디에 등록하고 관리하는지, 코드 실행 순서는 어떻게 관리하는지에 대한 매커니즘인 실행 컨텍스트를 이해해보겠습니다.
실행 컨텍스트의 매커니즘은 관리하는 대상에 따라 ‘스택’과 ‘렉시컬 환경’으로 구분할 수 있으며, 두 가지 개념을 중심으로 점진적으로 복잡해지는 코드를 살펴보도록 하겠습니다.
- 스택 - 코드 실행 순서를 관리합니다.
- 스택구조: 탑쌓기 놀이처럼 가장 아래에 있는 것을 빼려면 위에 있는 것들을 모두 제거해야 한다. 이는 먼저 들어온 것이 가장 나중에 빠지는 구조로 선입후출, FILO(First In Last Out) 구조라고도 부른다. 스택 구조에 포함시키는 것을 푸시(push), 제거하는 것을 팝(pop)이라고 한다.
- 렉시컬 환경 - 식별자와 스코프를 관리합니다.
1단계
var x = 1;
const y = 2;
console.log(x+y);
자바스크립트 엔진 동작 순서
1. 전역 객체 생성
2. 전역 코드 평가
2.1 전역 실행 컨텍스트 생성
2.2 전역 렉시컬 환경 생성
2.2.1 객체 환경 레코드 생성
2.2.1 선언적 환경 레코드 생성
2.3 this 바인딩
2.4 외부 렉시컬 환경에 대한 참조 결정
3. 전역 코드 실행
최종적으로 구성되는 실행 컨텍스트와 렉시컬 환경의 모식도는 위와 같습니다. 자바스크립트 엔진이 어떤 순서로 동작하여 위와 같은 모식도가 만들어지는지, 각 컴포넌트 및 기능들을 살펴보며 이해해보겠습니다.
1. 전역 객체 생성(window)
전역 코드 평가 이전에 전역 객체가 생성됩니다. 전역 객체에는 빌트인 전역 프로퍼티, 빌트인 전역함수, 표준 빌트인 전역객체가 추가되며 동작 환경에 따라 클라이인트 사이트 Web API 또는 특정 환경을 위한 호스트 객체를 포함합니다.
2. 전역 코드 평가
2.1 전역 실행 컨텍스트(Global Execution Context) 생성
- 비어있는 전역 실행 컨텍스트를 생성합니다.
- 전역 실행 컨텍스트를 실행 컨텍스트 스택에 푸시합니다.
- 스택의 가장 위에 존재하므로 실행 중인 실행 컨텍스트(running execution context)가 됩니다.
2.2 전역 렉시컬 환경(Global Lexical Environment) 생성
- 전역 렉시컬 환경을 생성하고 전역 실행 컨텍스트에 바인딩합니다.
- 전역 실행 컨텍스트의 렉시컬환경 컴포넌트에 바인딩
- 전역 렉시컬 환경은 2개의 컴포넌트, 전역 환경 레코드와 외부 렉시컬 환경에 대한 참조로 구성됩니다.
- 전역이 아닌 렉시컬 환경에서도 동일하게 2개의 컴포넌트로 구성됩니다.(환경 레코드 & 외부 렉시컬 환경에 대한 참조)
2.2.1 전역 환경 레코드(GlobalEnvironmentRecord) 생성
- 전역으로 선언된 변수 및 함수, 1.전역 객체 생성에서 생성된 전역 객체들을 제공합니다.
- let, const 키워드가 존재하지 않았던 ES6 이전에는 모든 전역 변수가 전역 객체의 프로퍼티와 같았습니다.(var 키워드로 변수 선언) 즉, 전역 객체가 전역 환경 레코드의 역할 수행했었습니다.
2.2.1.1 객체 환경 레코드(Object Environment Record) 생성
- 전역 환경 레코드를 구성하는 컴포넌트
- 1.전역 객체 생성에서 생성된 전역 객체인 BindingObject 객체와 연결됩니다.
- var 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수는 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 됩니다.
- 이는 전역 객체를 가리키는 식별자없이 프로퍼티 참조가 가능하다는 것으로, 예를 들어 alert를 window.alert 에서 전역 객체를 가리키는 window식별자 없이 사용 가능한 경우와 같습니다.
- var 키워드로 변수 선언 시, 식별자를 등록하는 선언 단계와 undefined를 암묵적으로 할당하며 등록된 변수를 위한 메모리 공간을 확보하는 초기화 단계가 동시에 진행됩니다.
- undefined라는 값이 할당된 상태이기 때문에, var 키워드로 선언된 변수는 코드 실행 단계 이전에 참조가 가능합니다. (변수 선언문 이전에 변수 참조가 가능한 현상을 변수 호이스팅이라고 합니다.)
- 함수의 경우, 함수 선언문은 함수 객체를 즉시 할당하고 var 키워드를 활용한 함수 표현식에서는 변수와 동일하게 동작합니다.
2.2.1.2 선언적 환경 레코드(Declarative Environment Record) 생성
- 전역 환경 레코드를 구성하는 컴포넌트
- let, const 키워드로 선언한 전역 변수를 관리합니다
- 전역 객체의 프로퍼티가 되지 않고 개념적인 블록(선언적 환경 레코드) 내에 존재합니다.
- 선언 단계와 초기화 단계가 분리되어 진행되기 때문에 런타임에서 변수 선언문에 도달하기 전에 변수 참조가 불가능한 일시적 사각지대(Temporal Dead Zone; TDZ)가 존재합니다.
- y변수에 바인딩되어 있는 uninitialized는 undefined와 같이 특정한 값이 할당된 것이 아닌, 어떤 값도 할당되지 않은 상태를 나타내는 표현입니다. 초기화 단계가 진행되지 않아 변수에 접근할 수 없는 상태임을 의미합니다.
2.3 this 바인딩
- 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 this가 바인딩됩니다. this를 참조하면, [[GlobalThisValue]] 내부 슬롯에 바인딩되어 있는 객체가 반환됩니다.
- 일반적으로 전역 코드에서 this는 전역 객체를 가리키므로 전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에는 전역 객체가 바인딩됩니다.
- this 바인딩은 전역 환경 레코드와 함수 환경 레코드에만 존재합니다.
2.4 외부 렉시컬 환경에 대한 참조(OuterLexicalEnvironmentReference) 결정
- 상위 스코프 즉, 현재 평가중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경을 가리킵니다.
- 이를 통해 단방향으로 연결된 스코프 체인을 구현합니다.
- 전역 코드의 경우, 참조할 렉시컬 환경이 없으므로 null 값이 할당되고, 이는 스코프 체인의 종점을 의미합니다.
3. 전역 코드 실행
- 전역 코드가 순차적으로 실행됩니다. 변수 할당문이 실행되며 전역 변수 x, y에 값이 할당됩니다. 정의된 함수가 있을 경우 함수가 호출됩니다.
- 변수 할당문 또는 함수 호출문을 실행하려면 변수 또는 함수 이름이 선언된 식별자인지 확인해야 하는 단계가 선행됩니다. 다시 말해, 실행 컨텍스트에 등록된 식별자만 참조 가능합니다.
- 식별자 결정(identifier resolution)은 다른 스코프에서 동일한 이름의 식별자가 존재할 경우, 어느 스코프의 식별자를 참조하면 되는지 결정하는 것입니다.
- 실행 중인 실행 컨텍스트에서 식별자를 검색 - 렉시컬 환경의 환경 레코드에 등록되어 있는가.
- 상위 스코프로 이동하여 식별자를 검색 (외부 렉시컬 환경에 대한 참조에 연결된 스코프)
- 모든 스코프를 검색했을 때 식별자가 없을 경우, 참조 에러를 발생시킴 - ReferenceError.
- console 식별자를 BindingObject를 통해 전역 객체에서 찾습니다.
- console 식별자에 바인딩된 log 메서드 객체가 존재하는지 검색합니다.
- 식별자 x, y 값들이 평가되어 연산된 값을 console.log 메서드에 전달해서 호출합니다
- 전역 실행컨텍스트가 스택에서 팝되며 종료됩니다
참고자료
- 이웅모. 『모던 자바스크립트 Deep Dive』. 위키북스, 2020. <23장. 실행컨텍스트>
'Language > JavaScript' 카테고리의 다른 글
Promise 개념 살펴보기(비동기, 힙메모리, 마이크로태스크 큐) (0) | 2025.02.12 |
---|---|
실행 컨텍스트 뿌시기 part2 (0) | 2023.08.27 |
자바스크립트 일반 (0) | 2023.06.24 |
[프로토타입] 프로토타입의 이해 (0) | 2022.12.25 |
[객체 기본] new 연산자와 생성자 함수 (0) | 2022.12.24 |