자바스크립트 엔진은 코드의 가장 위부터 아래로 순차적으로 코드를 실행하고, 엔진은 이 코드를 기계코드로 바꾸고 실행시키는 역할을 한다. 그리고 이 엔진은 Execution context stack, Heap으로 구성되어 있다.
실행 컨텍스트
렉시컬 환경: 식별자(변수, 함수, 클래스 등의 이름 등) 등록, 스코프 관리
실행 컨텍스트 stack: 코드 실행 순서 관리
렉시컬 환경을 제공하고, 실행 컨텍스트 stack으로 코드 실행 순서와 그 결과값을 관리하는 것을 실행 컨텍스트라 한다. 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.
LIFO: Last In First Out. 실행컨텍스트의 최상단에는 언제나 현재 실행 중인 코드의 실행 컨텍스트가 쌓이고, 다음 코드 실행시 코드의 실행 컨텍스트는 이 위에 쌓인다. 즉 언제나 최상단에는 가장 최신의 실행 컨텍스트가 존재하고, 컨텍스트 실행이 종료되면 가장 위에 있는 컨텍스트부터 stack에서 제거된다.
자바스크립트 엔진은 소스 코드를 평가와 실행의 단계로 나눈다.
- 평가(creation Phase): 런타임 이전. 실행 컨텍스트 생성, 변수, 함수 등의 선언문을 먼저 실행하여 실행컨텍스트의 스코프에 등록
- 실행(Execution Phase): 런타임. 선언문을 제외한 소스코드가 순차적으로 실행. 코드를 실행하면 필요한 정보(변수, 함수의 참조 등)을 실행 컨텍스트의 스코프에서 검색하여 취득. 취득한 후 식별자를 변경한 것과 같은 변경된 결과는 또 실행 컨텍스트의 스코프에 등록됨.
변수는 선언-초기화의 2단계를 거친다. 소스 코드의 평가단계에서 선언문을 먼저 실행하여 변수의 존재를 자바스크립트 엔진에게 알리고, 앞으로 값을 할당할 것을 대비하여 undefined로 초기화하고 메모리 공간을 확보해둔다. 이렇게 런타임 이전에 선언문에 대한 실행이 이루어지기 때문에 변수 선언 이전에 값을 참조해도 언제나 undefined 출력되는 변수 호이스팅이 발생한다. 소스 코드가 실행되는 시점에는 변수가 실행 컨텍스트의 스코프 상에 존재하는지 확인하고, 존재한다면 변수에 값을 할당하고, 이 결과를 실행 컨텍스트에 등록한다.
소스코드에 따라 각각의 실행 컨텍스트를 생성한다.
- 전역 코드: 전역에 존재하는 소스코드, 전역 스코프, 전역 실행 컨텍스트. 전역에 정의된 함수, 클래스 등의 내부 코드는 포함안함.
- 함수 코드: 함수 내부에 존재하는 소스코드, 지역 스코프, 함수 실행 컨텍스트. 함수 내부에 중첩된 함수, 클래스 등의 내부 코드는 포함하지 않고, 지역 변수, 매개변수, arguments 객체를 관리
- eval 코드
- 모듈 코드
실행 컨텍스트가 하는 일
- 전역 코드 평가 - 실행
- 순차적으로 전역 코드를 실행하다가 함수가 호출되면 순서를 변경하여 함수 내부로 진입한다.
- 함수 코드 평가 - 실행
위의 평가-실행 과정
에서 가장 중요한 키워드는 스코프를 기억하고 스코프 체인을 형성, 식별자를 등록하고 관리, 코드 실행 순서를 관리하는 것이다.
전역 실행 컨텍스트 생성 | 과정 | 함수 실행 컨텍스트 생성 | 과정 |
---|---|---|---|
전역 객체 생성 | 코드 평가 이전에 생성됨. | 함수 코드 제어권 확보 | 전역 코드를 실행하다가 함수호출을 만나면 제어권이 함수 내부로 이동 |
전역 코드 평가 | 소스코드 로드 후 전역 코드 평가 | 함수 코드 평가 | |
전역 실행 컨텍스트 생성 | 실행 컨텍스트 stack에 push됨. | 함수 실행 컨텍스트 생성 | 실행 컨텍스트 stack에 push됨. |
전역 렉시컬 환경 생성 | 전역 렉시컬 환경과 전역 실행 컨텍스트의 렉시컬 환경을 바인딩. | 함수 렉시컬 환경 생성 | 함수 렉시컬 환경과 함수 실행 컨텍스트 바인딩 |
전역 환경 레코드 생성 | 객체 환경 레코드(Object Environment Record): var 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수, 빌트인 전역 프로퍼티와 빌트인 전역 함수, 표준 빌트인 객체를 관리 | 함수 환경 레코드 생성 | 매개변수, arguments객체, 함수 내부에서 선언한 지역 번수 및 중첩 함수 등록 및 관리 |
선언적 환경 레코드(Declarative Environment Record): let, const 키워드로 선언한 전역 변수를 관리 | |||
객체 환경 레코드 생성 | BindingObject라고 부르는 객체와 연결되어 전역 객체의 프로퍼티와 메서드가 됨. (var 키워드, 함수 선언문으로 정의한 전역함수의 경우에만) | ||
var 키워드: 전역 객체에 변수 식별자 등록 후 undefined를 바인딩 -> 변수 호이스팅 | |||
함수 선언문: 전역 객체에 변수 식별자 등록 후 함수 객체를 할당 -> 함수 호이스팅 | |||
선언적 환경 레코드 생성 | let, const 키워드로 선언한 전역 변수를 등록하고 관리. 전역 객체의 프로퍼티가 되지 않음. | ||
this 바인딩 | 전역 환경 레코드, 함수 환경 레코드에만 존재. 전역 환경 레코드에 바인딩되어 있는 객체 반환. | this 바인딩 | this는 함수 호출 방식에 따라 결정됨. (일반 함수로 호출: this = 전역객체) |
외부 렉시컬 환경에 대한 참조 결정 | 현재 평가 중인 소스코드의 렉시컬 환경, 즉 상위 스코프를 통해 스코프 체인 구성. 전역 렉시컬 환경을 스코프 체인의 종점이므로 null이 할당됨. | 외부 렉시컬 환경에 대한 참조 결정 | 함수 정의가 평가되는 시점에 참조 할당. |
전역 코드 실행 | 코드를 top-down으로 순차적으로 실행하며 실행 컨텍스트에서 식별자 검색 | 함수 코드 실행 | 실행 컨텍스트의 렉시컬 환경에서 식별자 검색 |
렉시컬 환경
식별자와 스코프를 관리한다.
생성 | 역할 |
---|---|
Execution Context | Execution Context가 생성되면서 Lexical Environment를 생성함. |
Execution Context 프로퍼티 Lexical Environment | 실행컨텍스트의 Lexical Environment와 렉시컬 환경을 연결 |
Lexical Environment | 실행컨텍스트의 Lexical Environment와 바인딩됨. |
Environment Record | 식별자 등록, this 바인딩 된 값을 관리 |
Outer Lexical Environment Reference | 상위 스코프를 관리. 이를 통해 스코프 체인 구성 |
References
poiemaweb
JavaScript Internals: JavaScript engine, Run-time environment & setTimeout Web API