오늘 알아볼 개념은 실행 컨텍스트와 콜 스택이다.
이러한 순서로 진행해보도록 하겠다.
실행 컨텍스트는 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이다.
-ECMAScript
쉽게 말해 코드가 실행되는 환경인 것으로 이해되는데, 대표적으로 두 가지 타입의 실행 컨텍스트가 있다고 한다.
자바스크립트 엔진은 코드가 실행되면 가장 먼저 전역 실행 컨텍스트를 생성한다. 또한 실행에 필요한 정보들을 형상화하기 위해 물리적 객체 형태로 저장하는데,
아무 코드가 없더라도 자바스크립트 엔진에서 코드를 실행하는 시점에 전역 실행 컨텍스트는 생성된다.
전역 실행 컨텍스트는 코드가 실행되는동안 단 한번만 생성된다.
이 과정에서 코드 전반을 관리하는 전역 객체가 생성되어 우리가 알고 있는 window
객체를 생성하고, this
가 window
객체를 가리키도록 한다.
함수 실행 컨텍스트는 함수 선언이 아닌 함수 "호출" 시에 생성된다.
이는 전역 실행 컨텍스트와 다르게 함수가 호출되는 모든 시점에 생성된다. 그리고 이 함수 실행 컨텍스트는 자신만의 실행 컨텍스트를 가진다.
실행 컨텍스트는 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이라고 정의했지만, 코드 실행 시에는 자바스크립트 엔진에서 이를 물리적 객체 형태로 형상화 하기 때문에, 이에 따른 프로퍼티가 생성되게 된다.
변수 객체
변수 객체는 엔진에서 참조되어 코드에서는 접근할 수 없는 객체이다.
여기에는 변수, 함수 선언, 함수 실행 컨텍스트에만 존재하는 매개변수 및 인자 정보가 담기게 된다.
1 ) 전역 실행 컨텍스트의 경우
전역 변수, 전역 함수를 프로퍼티로 소유하게 된다.
2 ) 함수 실행 컨텍스트의 경우
지역 변수, 내부 함수, 매개변수와 인자 정보를 담고 있는 arguments object를 프로퍼티로 소유하게 된다.
스코프 체인(Scope Chain)
스코프 체인은 Identifiers(식별자)를 찾는 일련의 과정이다.
실행 컨텍스트에 저장되는 스코프 체인의 개념은 해당 전역 혹은 함수 실행 컨텍스트가 참조할 수 있는 변수와 함수 선언에 대한 리스트를 의미한다.
자바스크립트 엔진은 스코프 체인을 통해 렉시컬 스코프를 파악한다. 따라서 중첩된 함수 실행 컨텍스트의 경우 해당 함수의 스코프부터 전역 스코프까지 탐색이 가능하도록 하기 위해, 스코프 체인에는 현재 실행 컨텍스트의 지역 변수, 내부 함수의 정보를 담고 있는 객체(활성 객체)를 시작으로 순차적으로 부모 실행 컨텍스트의 활성 객체의 리스트가 저장되며, 마지막으로는 전역 실행 컨텍스트의 전역 객체가 저장된다.
this
this 프로퍼티에는 this 값이 할당된다. this에 할당되는 값은 함수 호출 패턴에 의해 결정된다.
호출 스택은 여러 함수들(functions)을 호출하는 스크립트에서 해당 위치를 추적하는 인터프리터 (웹 브라우저의 자바스크립트 인터프리터같은)를 위한 메커니즘이다.
-MDN Web Docs
여기에서 인터프리터란 프로그래밍 언어의 소스 코드를 바로 실행하는 컴퓨터 프로그램 또는 환경을 말한다.
(나중에 인터프리터에 관한 내용으로 포스팅을 따로 진행해보겠다.)
인터프리팅이라는 작업 자체가 자바스크립트 엔진 안에서 진행되는 작업이기 때문에,
콜 스택은 쉽게 말해 자바스크립트 엔진에서 생성한 실행 컨텍스트를 저장하는 자료구조의 개념이라고 생각하면 좋을 것 같다.
이름에서 알 수 있듯 스택 자료 구조형으로 되어 있다.(push-pop 형식)
//step 1
function first() {
console.log('first'); // step 3, step 4
second(); //step 5 // step 8
}
function second() {
console.log('second'); // step 6, step 7
}
first(); //step 2 // step 9
//step 10
만약 이러한 코드가 실행된다고 가정할 때, 콜 스택에 일어나는 일은 이러할 것이다. 주석으로 알아먹기 어렵게 적어 둔 단계를 그림으로 표현하자면,
이러한 형태로 볼 수 있다. 이 그림은 콜 스택을 시각화한 것인데, 이를 쉽게 풀어보는 것으로 이 글을 마치겠다.
step 1: 코드가 실행이 되자마자 전역 실행 컨텍스트를 생성하고 콜 스택에 저장한다.
step 2: 코드 최하단에 위치한 first()
라는 함수 호출문에서 함수 실행 컨텍스트가 생성되어 콜 스택에 저장된다.
step 3: 호출된 first
함수 내부의 console.log('first')
호출문에서 함수 실행 컨텍스트가 생성 되어 콜 스택에 저장된다.
step 4: console.log('first')
실행 컨텍스트가 완료되어 콜 스택에서 제거된다.
step 5: 호출된 first
함수 내부의 second()
호출문에서 함수 실행 컨텍스트가 생성되어 콜 스택에 저장된다.
step 6: 호출된 second
함수 내부의 console.log('second')
호출문에서 함수 실행 컨텍스트가 생성되어 콜 스택에 저장된다.
step 7: console.log('second')
실행 컨텍스트가 완료되어 콜 스택에서 제거된다.
step 8: second
함수 실행 컨텍스트가 완료되어 콜 스택에서 제거된다.
step 9: first
함수 실행 컨텍스트가 완료되어 콜 스택에서 제거된다.
step 10: 모든 코드가 실행되었기 때문에 전역 실행 컨텍스트가 완료되어 콜 스택에서 제거된다.