티스토리 뷰
실행 컨텍스트: 자바스크립트의 동작 원리를 담고 있는 핵심 개념
- 스코프를 기반으로 식별자와 바인딩된 값을 관리하는 방식
- 호이스팅이 발생하는 이유
- 클로저의 동작 방식
- 태스크 큐와 함께 동작하는 이벤트 핸들러
- 비동기 처리의 동작 방식
23.1 소스코드의 타입
소스코드는 실행 컨텍스트를 생성함
타입에 따라 실행 컨텍스트를 생성하는 과정(코드가 평가되는 시점)과 관리 내용이 다름
1. 전역 코드
전역에 존재하는 소스코드, 전역에 정의된 함수, 클래스 등의 내부 코드는 포함하지 않음
최상위 스코프인 전역 스코프를 생성
var 키워드로 선언된 전역 변수(프로퍼티)와 함수 선언문으로 정의된 전역 함수(메서드)를 참조하기 위해 전역 객체와 연결돼야 함
전역 코드가 평가되면 전역 실행 컨텍스트가 생성됨
2. 함수 코드
함수 내부 소스코드, 함수 내부에 중첩된 함수, 클래스 등의 내부 코드는 포함되지 않음
지역 스코프 생성, 지역 변수, 매개변수, arguments 객체를 관리
스코프 체인의 일부로 연결
함수 코드가 평가되면 함수 실행 컨텍스트가 생성됨
3. eval 코드
빌트인 전역 함수 eval 함수에 인수로 전달되어 실행되는 코드
strict mode에서만 독자적인 스코프 생성
eval 코드가 평가되면 eval 실행 컨텍스트가 생성됨
4. 모듈 코드
모듈 내부에 존재하는 소스코드, 모듈 내부 함수, 클래스 등의 내부 코드는 포함되지 않음
모듈별로 독립적인 모듈 스코프 생성
모듈 코드가 평가되면 모듈 실행 컨텍스트가 생성됨
23.2 소스코드의 평가와 실행
소스코드 평가 과정
- 실행 컨텍스트 생성
- 변수, 함수 등의 선언문을 먼저 실행하여 스코프(렉시컬 환경의 환경 레코드)에 등록
런타임
- 선언문을 제외한 소스코드가 순차적으로 실행
- 소스코드 실행 중 필요한 정보를 스코프에서 취득
- 변수 값 변경 등의 실행 결과를 스코프에 다시 등록
1. 전역 코드 평가
전역 스코프에 전역 변수와 전역 함수가 등록됨(전역 객체의 프로퍼티와 메서드가 됨)
(참고: 전역 객체의 프로퍼티와 메서드는 스코프 체인에 등록되어 있지 않아도 검색할 수 있음)
2. 전역 코드 실행
런타임 시작, 전역 코드가 순차적으로 실행(값 할당, 함수 호출)
함수가 호출되면 전역 코드의 실행을 일시 중단하고 함수로 진입
3. 함수 코드 평가
함수 코드 실행 전 평가
지역 스코프에 매개변수와 지역 변수, arguments 객체가 등록되고 this 바인딩이 결정됨
4. 함수 코드 실행
런타임이 시작되어 함수 코드가 순차적으로 실행
23.3 실행 컨텍스트의 역할
1. 식별자를 스코프를 구분하여 등록하고, 상태 변화를 지속적으로 관리
2. 스코프 체인을 통해 상위 스코프로 이동하며 식별자를 검색할 수 있도록 스코프는 중첩 관계로 형성되어야 함
3. 현재 실행 중인 코드의 실행 순서를 변경(함수 호출, 함수 실행이 종료된 후)할 수 있어야 함
소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역
스코프에 식별자를 등록하고 관리(렉시컬 환경), 코드 실행 순서 관리(실행 컨텍스트 스택)를 구현한 내부 메커니즘
23.4 실행 컨텍스트 스택(stack)
코드 실행 순서 관리
코드가 평가되고 실행 컨텍스트가 생성되면 실행 컨텍스트 스택에 push됨
실행할 코드가 남지 않았다면 해당 실행 컨텍스트는 실행 컨텍스트 스택에서 pop됨
스택의 최상위 = 실행 중인 실행 컨텍스트(running execution context)
23.5 렉시컬 환경
스코프와 식별자를 관리
식별자와 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 기록하는 자료구조
실행 컨텍스트를 구성하는 컴포넌트
스코프를 구분하여 식별자를 등록하고 관리하는 저장소 역할을 하는 렉시컬 스코프*의 실체
* 함수를 어디에 선언하였는지에 따라 상위 스코프가 결정되는 것(함수 호출 위치 X)
실행 컨텍스트는 LexicalEnvironment 컴포넌트와 VariableEnvironment 컴포넌트로 구성됨
생성 초기에는 두 컴포넌트가 동일한 렉시컬 환경 하나를 참조하지만,
상황에 따라 VariableEnvironment 컴포넌트를 위한 새로운 렉시컬 환경을 생성하여 참조값이 달라질 수 있음
렉시컬 환경은 두 개의 컴포넌트로 구성됨
- 환경 레코드 EnvironmentRecord
스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩된 값을 관리하는 저장소
소스코드 타입에 따라 관리하는 내용에 차이가 있음
- 외부 렉시컬 환경에 대한 참조 OuterLexicalEnvironmentReference
상위 스코프. 해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경
스코프 체인(단방향 링크드 리스트) 구현
23.6 실행 컨텍스트의 생성과 식별자 검색 과정
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); // 42
1. 전역 객체 생성
전역 코드가 평가되기 이전에 생성됨
빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체가 추가되고,
동작 환경에 따라 클라이언트 사이드 Web API 또는 특정 환경을 위한 호스트 객체 포함
전역 객체도 Object.prototype을 상속받음(프로토타입 체인의 일원)
2. 전역 코드 평가
1. 전역 실행 컨텍스트 생성
전역 실행 컨텍스트 생성, 실행 컨텍스트 스택에 푸시됨
2. 전역 렉시컬 환경 생성
전역 렉시컬 환경을 생성하고 전역 실행 컨텍스트에 바인딩
2.1 전역 환경 레코드 생성
전역 스코프, 전역 객체의 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체 제공
객체 환경 레코드와 선언적 환경 레코드로 구성됨*
두 레코드가 협력하여 전역 스코프와 전역 객체(전역 변수의 전역 객체 프로퍼티화)를 관리
* var로 선언한 전역 변수와 let, const로 선언한 전역 변수를 구분하기 위해
2.1.1 객체 환경 레코드(ObjectEnvironmentRecord) 생성
var 키워드로 선언한 전역 변수, 함수 선언문으로 정의한 전역 변수, 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체 관리
BindingObject 객체(1에서 생성된 전역 객체)와 연결되고, 이 연결을 통해 전역 객체의 프로퍼티와 메서드가 됨
전역 객체를 가리키는 식별자(window) 없이 전역 객체의 프로퍼티(alert)를 참조할 수 있는 메커니즘
평가 단계에서 var 키워드로 선언한 변수는 암묵적으로 undefined가 바인딩되고(let, const는 초기화되지 않음),
함수 선언문으로 정의한 함수는 함수 객체가 즉시 할당됨
선언 전 참조: 변수-undefined, 함수-호출 가능(변수/함수 호이스팅의 차이)
2.1.2 선언적 환경 레코드(DeclarativeEnvironmentRecord) 생성
let, const 키워드로 선언한 전역 변수 관리
개념적인 블록
전역 객체의 프로퍼티로 참조할 수 없음
선언 단계 O, 초기화 단계는 거치지 않기 때문에 할당 전 참조하면 런타임에 TDZ 존재(참조 시점~할당 시점)
2.2 this 바인딩
전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 this가 바인딩됨(전역 객체 바인딩)
this 바인딩은 전역 환경 레코드와 함수 환경 레코드에만 존재
- 객체 환경 레코드와 선언적 환경 레코드에는 없음
2.3 외부 렉시컬 환경에 대한 참조 결정
전역 코드이기 때문에 상위 스코프가 없음(스코프 체인의 종점) => null
-
3. 전역 코드 실행
식별자 결정: 어느 스코프의 식별자를 참조할 지 결정
식별자 결정(식별자 검색)에 실패하면 참조 에러 발생
4. foo 함수 코드 평가
1. 함수 실행 컨텍스트 생성
함수 실행 컨텍스트 생성, 함수 렉시컬 환경이 완성된 후 실행 컨텍스트 스택에 푸시됨
2. 함수 렉시컬 환경 생성
함수 렉시컬 환경을 생성하고 함수 실행 컨텍스트에 바인딩
2.1 함수 환경 레코드 생성
매개변수, arguments 객체, 함수 내부에서 선언한 지역 변수와 중첩 함수를 등록하고 관리
2.2 this 바인딩
함수 환경 레코드의 [[ThisValue]] 내부 슬롯에 this가 바인딩됨(함수 호출 방식에 따라 this가 달라짐)
2.3 외부 렉시컬 환경에 대한 참조 결정
foo 함수 정의가 평가된 시점(전역 코드 평가)에 실행 중인 실행 컨텍스트(전역 실행 컨텍스트)의 렉시컬 환경의 참조가 할당됨
자바스크립트 엔진은 함수 정의를 평가하여 함수 객체를 생성할 때 함수의 상위 스코프를 함수 객체의 내부 슬롯 [[Environment]]에 저장함(=> 렉시컬 스코프를 구현하는 메커니즘)
외부 렉시컬 환경에 대한 참조에 할당되는 것이 [[Environment]]에 저장된 렉시컬 환경의 참조
-
5. foo 함수 코드 실행
6. bar 함수 코드 평가
7. bar 함수 코드 실행
1. z에 5 할당
2. 스코프 체인에서 console 식별자 검색
스코프 체인: 현재 실행 중인 실행 컨텍스트의 렉시컬 환경에서 시작하여 외부 렉시컬 환경에 대한 참조로 이어지는 렉시컬 환경의 연속
bar 렉시컬 환경 -> foo 렉시컬 환경 -> 전역 렉시컬 환경
3. log 메서드 검색
console 객체의 프로토타입 체인을 통해 메서드 검색
4. 표현식 a + b + x + y + z 평가
스코프 체인에서 식별자 검색
a, x, y => foo 렉시컬 환경
b, z => bar 렉시컬 환경
5. console.log 메서드 호출
-
8. bar 함수 코드 실행 종료
실행 컨텍스트 스택에서 bar 함수 실행 컨텍스트가 pop
bar 함수 렉시컬 환경이 어딘가에서 참조되고 있다면 유지, 아니라면 gc에 의해 소멸
9. foo 함수 코드 실행 종료
10. 전역 코드 실행 종료
7. 실행 컨텍스트와 블록 레벨 스코프
var는 함수의 코드 블록만 지역 스코프로 인정 => 함수 레벨 스코프
let, const는 모든 코드 블록을 지역 스코프로 인정 => 블록 레벨 스코프
let x = 1;
if (true) {
let x = 10;
console.log(x); // 10
}
console.log(x); // 1
if 문의 코드 블록을 위한 블록 레벨 스코프가 생성되야 하는데
선언적 환경 레코드를 갖는 렉시컬 환경을 생성하여 기존 전역 렉시컬 환경을 교체
새 렉시컬 환경의 외부 렌시컬 환경에 대한 참조는 if 문이 실행되기 이전의 렉시컬 환경인 전역 렉시컬 환경을 가리킴
'책' 카테고리의 다른 글
[딥다이브] 25. 클래스(1) (0) | 2024.07.03 |
---|---|
[딥다이브] 24. 클로저 (0) | 2024.06.25 |
[딥다이브] 22. this (0) | 2024.06.09 |
[딥다이브] 21. 빌트인 객체 (1) | 2024.06.04 |
[딥다이브] 20. strict mode (0) | 2024.06.04 |