1. 자바 스크립트의 소스코드
자바스크립트에서 소스코드는 4가지로 분류할 수 있다
소스코드 타입 설명
전역 코드 | 전역에 존재하는 소스 코드. 단 전역에 정의된 함수, 클래스 등의 내부 코드는 미포함 |
함수 코드 | 함수 내부에 존재하는 소스코드. 중첩된 함수, 클래스 등의 내부 코드는 미포함 |
eval 코드 | 빌트인 전역 함수 eval 에 의해 실행되는 소스코드 eval은 보안상의 문제, 성능상의 문제가 있어 사용을 금함 |
모듈 코드 | 모듈 내부에 존재하는 소스코드 모듈 내부의 함수, 클래스 등의 내부 코드는 미포함 |
2. 소스코드의 평가와 실행
자바스크립트 엔진은 소스코드를 두 개의 과정에 걸쳐서 처리한다
- 소스코드의 평가
- 소스코드의 실행
소스코드의 평가
- 이 과정에서 실행 컨텍스트가 생성된다
- 자바스크립트 엔진은 런타임 이전(실행 컨텍스트 실행 시점 이전)에 먼저 선언문을 찾아 평가한다
- 즉 식별자들을 먼저 찾아서 초기화하는 과정을 진행한다
- 선언문의 식별자들을 키로 실행 컨텍스트가 관리하는 스코프에 등록한다
- 이때의 스코프가 렉시컬 환경의 환경 레코드다.
소스코드의 실행
- 소스코드 평가가 끝나면 선언문을 제외한 소스코드가 순차적으로 실행된다. 즉 런타임이 시작된다
- 이때, 실행에 필요한 정보들(변수, 함수의 참조 등)을 실행 컨텍스트가 관리하는 스코프에서 찾는다
- 실행이 완료되면 변수 값의 변경 등의 결과를 다시 실행 컨텍스트가 관리하는 스코프에 기록한다
3. 호이스팅
// 실행 순서
console.log(name) // (2)
var name; // (1)
name = 'liebe' // (3)
console.log(name) // (4)
(1) 런타임 이전에 자바스크립트 엔진은 let name; 을 가장 먼저 실행한다 (선언문 실행)
- 이 과정에서 일어나는 일은 아래와 같이 정리할 수 있다
- 변수 name 을 실행 컨텍스트가 관리하는 스코프에 등록한다
- ⇒ 정확히는 실행 컨텍스트의 변수 객체에 등록하고 이 객체를 스코프가 참조한다
- 변수 name 이 가리킬 메모리(주소)를 확보하고 undefined 로 초기화한다 ⇒ 이를 초기화 단계라고 부른다
- 이후, 다른 선언문은 없기에 소스코드 평가 과정은 여기서 마친다
(2) undefined 가 출력된다
- name 변수를 실행 컨텍스트가 관리하는 스코프에서 확인한다
- name 이라는 변수가 존재하지만 초기화된 undefined 를 값으로 가져온다
(3) name 변수에 ‘liebe’ 값이 할당된다
- name 변수를 실행 컨텍스트가 관리하는 스코프에서 확인한다
- 해당 변수가 가리키는 메모리에 값을 넣는다
- 이 할당의 결과를 다시 실행 컨텍스트에 등록한다
(4) liebe 가 출력된다
- name 을 실행 컨텍스트가 관리하는 스코프에서 확인하고 그 값인 ‘liebe’ 를 가져온다
사실, let 과 const 도 호이스팅이 일어난다.
let 과 const 는 var 키워드의 문제점, 특히 이 호이스팅과 같은 문제점을 막기 위해서 등장한 키워드로 알고 있다.
정확히는 let과 const 도 호이스팅이 일어난다
⇒ 자바스크립트 엔진 구동 원리상, 모든 식별자와 선언문은 런타임 이전에 먼저 실행되기 때문
다만, name 을 실행 컨텍스트에 등록화는 과정에서 메모리를 확보하는 초기화 단계를 진행하지 않기 때문에 참조 조차 안 되는 것 (ReferenceError)
호이스팅이 일어난다는 것은 아래의 코드를 통해 알 수 있다
let a = 10;
{
console.log(a) // ReferenceError: a is not defined
let a = 200
}
4. 실행 컨텍스트가 하는 일
위의 간단한 예시에서 보면 알 수 있듯이, 코드가 실행되기 위해서는 스코프, 식별자, 코드의 실행 순서를 관리할 수 있는 것이 필요하다
⇒ 이게 바로 실행 컨텍스트
실행 컨텍스트는 소스코드를 실행하는 데 필요한 환경을 제공하고, 코드의 실행 결과를 관리하는 영역이다
- 식별자들(변수, 함수, 클래스 등의 이름), 스코프 ⇒ 렉시컬 환경으로 관리
- 코드의 실행 순서 관리하는 메커니즘 ⇒ 실행 컨텍스트 스택으로 관리