소스코드의 타입
ㄱ. 전역코드
- 최상위 코드인 전역 스코프를 생성 후, 전역 객체와 연결
- 이를 위해 전역 코드가 평가되면 전역 실행 컨텍스트가 생성됨
ㄴ. 함수코드
- 함수마다의 지역 스코프를 생성하고, 지역변수|매개변수|arguments 객체 등을 관리함
- 생성한 지역 스코프를 전역 스코프에서 시작하는 스코프 체인의 일원으로 연결해야 함
- 이를 위해 함수 코드가 평가되면 함수 실행 컨텍스트가 생성됨
ㄷ. eval코드 (빌트인 전역 함수인 eval 함수에 인수로 전달되어 실행되는 소스코드)
- strict mode에서 자시만의 독자적인 스코프를 생성함
- 이를 위해 eval 코드가 평가되면 eval 실행 컨텍스트가 생성됨
ㄹ. 모듈코드
- 모듈별로 독립적인 모듈 스코프를 생성
- 이를 위해 모듈 코드가 평가되면 모듈 실행 컨텍스트가 생성됨
모든 소스코드는 실행에 앞서 평가 과정을 거치며 코드를 실행하기 위한 준비를 함
다시 말하면 js엔진은 소스코드를 "소스코드의 평가" 와 "소스코드의 실행" 과정으로 나누어 처리함
- 소스코드 평가 과정 : 실행 컨텍스트를 생성하고 변수,함수 등의 선언문을 먼저 처리 후,
생성된 변수, 함수 식별자를 키로 이용하여 실행 컨텍스트가 관리하는 스코프에 등록함
- 소스코드 실행 과정 : 평가 과정이 끝난 후, 선언문을 제외한 소스코드가 순차적으로 실행됨
=> 소스코드를 평가하면서 선언문을 먼저 실행해 여러 가지 실행 컨텍스트의 스코프에 선언된 변수,함수들을 등록하고,
제각각의 실행컨텍스트의 스코프를 이용해 소스코드를 실행한다.
실행 컨텍스트는
- 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행결과를 관리하는 영역
- 식별자를 등록하고 관리하는 스코프와 실행 순서 관리를 구현한 내부 매커니즘으로 모든 코드는 실행 컨텍스트를 통해 실행되고 관리됨
전역코드와 함수코드로 이루어진 예시를 보고 js엔진이 이를 어떻게 평가|실행 하는지 기술
const x = 1;
const y = 2;
function foo(a) {
const x = 10;
const y = 20;
console.log( a + x + y ); // 130
}
foo(100);
console.log( x + y ); // 3
1. 전역코드 평가과정 : 전역 변수와 전역 함수가 전역 실행 컨텍스트에서 관리하는 전역 스코프에 등록
2. 전역코드 실행과정 : 평가 과정이 끝난 후, 런타임이 시작되어 전역코드가 순차적으로 실행됨
이 때, 전역변수에 값이 할당되고 함수가 호출됨
함수가 호출되면 전역 코드의 실행을 일시 중단하고 함수 내부로 진입
3. 함수코드 평가과정 : 함수 호출에 의해 전역코드 실행과정이 중단되고 함수코드 평가과정이 실행됨
매개변수와 지역변수 선언문이 먼저 실행되고,
함수 실행 컨텍스트가 관리하는 스코프에 매개변수와 지역변수가 등록됨
this 바인딩도 이 때 결정됨
4. 함수코드 실행과정 : 평가 과정이 끝난 후, 런타임이 시작되어 함수코드가 순차적으로 실행됨
이 때, 지역변수에 값이 할당되고 console.log 메서드가 호출됨
console 객체는 스코프 체인을 통해 전역객체에서 찾아옴
위 과정으로 실행컨텍스트 스택을 설명하자면,
전역실행컨텍스트가 실행컨텍스트 스택에 쌓이고, 그 후 foo함수실행컨텍스트가 실행컨텍스트 위에 push됨
그럼 foo함수코드로 순서가 넘어가며 foo함수코드의 평가|실행 과정이 모두 끝난 후에 foo함수실행컨텍스트가 pop되어 다시 전역코드를 수행한다.
렉시컬 환경
렉시컬 환경은 식별자|식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조며 실행 컨텍스트의 한 컴포넌트임
실행컨텍스트 스택이 코드의 실행 순서를 관리한다면 렉시컬 환경은 스코프와 식별자를 관리해주는 테이블이라고 해석했음
실행컨텍스트는 "렉시컬 환경 컴포넌트","variable 환경 컴포넌트" 로 나뉘며,
렉시컬 환경 컴포넌트는 두 개의 컴퍼넌트로 구성됨
- 환경 레코드(Environment Record) : 스코프에 포함된 식별자를 등록하고 식별자에 부여된 값을 관리하는 저장소
- 외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference) : 상위 스코프(상위코드의 렉시컬 환경)를 가리킴
이를 통해 단방향 리스트인 스코프 체인을 구현함
아래 코드로 각 평과과정,실행과정을 다시 설명함
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. 전역 실행 컨텍스트 생성
2. 전역 렉시컬 환경 생성
2-1. 전역 환경 레코드 생성
2-1-1. 객체 환경 레코드 생성
2-1-2. 선언적 환경 레코드 생성
2-2. this 바인딩
2-3. 외부 렉시컬 환경에 대한 참조 결정
* 2-1. 전역 환경 레코드 생성 :
기존의 var 키워드로 선언한 전역 변수와
ES6의 let, const 키워드로 선언한 전역 변수를 구분하기 위해
전역 환경 레코드는 "객체 환경 레코드", "선언전 환경 레코드" 로 구성되어있다.
객체 환경 레코드는 기존의 var 키워드로 선언한 전역 변수와
함수 선언문으로 정의한 전역 함수, 빌트인 객체등을 관리하고
선언적 환경 레코드는 let, const 키워드로 선언한 전역 변수를 관리함
* 2-1-1. 객체 환경 레코드 생성 :
이 레코드에서 관리하는
var 키워드, 함수선언문으로 정의한 전역함수는
객체 환경 레코드에 연결된 BindingObejct 객체를 통해 전역 객체의 프로퍼티와 메서드가 됨
즉 전역객체를 바인딩한 참조객체 (window) 등에서
바로 접근할 수 있음
또한 객체 환경 레코드에서 관리하는 식별자는
전역 코드 평가과정에서 선언 단계와 초기화 단계가 동시에 진행되므로
var 키워드로 생성한 변수의 hoisting이 설명됨
* 2-1-2. 선언적 환경 레코드 생성 :
let, const 키워드로 선언한 변수는 전역 객체의 프로퍼티가 되지 않고
개념적인 블록 내에 존재하게됨
따라서 window와 같은 전역 객체에서 바로 접근할 수 없음
또한 let, const 키워드로 선언한 변수는
선언 단계와 초기화 단계가 나누어서 실행되며
런타임에 들어가게 된 후, 선언 단계에 도달하기 전까지 TDZ 존에 빠지게 된다.
- 전역 코드 실행
전역 변수 x, y 에 값이 할당된 후, foo 함수가 호출됨
값을 할당할 때는 실행 중인 실행 컨텍스트에의 렉시컬 환경에서 식별자를 검색하고,
탐색에 성공하였다면 할당,
탐색실패하였다면 외부 렉시컬 환경에 대한 참조가 가리키는 상위 렉시컬 환경(상위 스코프)를 참조한다.
현재 실행 컨텍스트는 전역 실행 컨텍스트. 즉 최상위 실행 컨텍스트이므로 상위 스코프를 참조할 수 없다.
- foo 함수 코드 평가
1. 함수 실행 컨텍스트 생성
2. 함수 렉시컬 환경 생성
2-1. 함수 환경 레코드 생성
2-2. this 바인딩
2-3. 외부 렉시컬 환경에 대한 참조 결정
- foo 함수 코드 실행
지역 변수 x,y에 값이 할당되고, bar 함수가 호출됨
- bar 함수 코드 평가
- bar 함수 코드 실행
bar 함수 실행 중에 console이라는 객체를 만난다.
console은 전역 객체의 일부라서
스코프 체인을 이용하여 최상위 전역 객체까지 거슬러 올라가야 한다.
console을 참조할 시 먼저 bar함수 실행 컨텍스트의 렉시컬 환경(환경 레코드)에서 console 을 찾으며
탐색 실패시 외부 렉시컬 환경에 대한 참조에서 console을 탐색한다.
실패 시 최상단 실행 컨텍스트의 렉시컬 환경에 도달할 때 까지 반복하며
결국 전역 실행 컨텍스트에서 console을 찾을 것임
- bar 함수 코드 실행 종료
bar 실행 컨텍스트가 실행 컨텍스트 스택에서 pop되며 제거될 것임
그러나 실행될 일이 없다고 바로 bar 실행 컨텍스트의 렉시컬 환경까지 즉시 소멸하진 않음
렉시컬 환경은 실행 컨텍스트에 의해 참조되기는 하지만 독립적인 객체임
따라서 누군가에 의해 bar 함수 렉시컬 환경을 참조 당하고 있다면
bar 함수의 렉시컬 환경은 소멸되지 않음
역으로 참조 당하고 있지 않다면 그때서야 가비지 컬렉터에 의해 소멸됨
- foo 함수 코드 실행 종료
- 전역 코드 실행 종료
'js > 작동방식' 카테고리의 다른 글
node 비동기 작업의 실행원리 (process.nextTick) (0) | 2024.12.05 |
---|---|
js 일급객체(함수) (0) | 2023.02.15 |
js node, npm, cli (0) | 2022.01.15 |
js hoisting (0) | 2022.01.14 |
댓글