실행 컨텍스트
실행 컨텍스트(Execution Context)란 무엇인가요? ⭐⭐⭐
실행 컨텍스트
소스코드를 실행하는 데 필요한 환경을 제공하고, 코드의 실행 결과를 실제로 관리하는 영역이다.
좀 더 구체적으로, 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 메커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.
식별자, 스코프는 실행 컨텍스트의 렉시컬 환경으로 관리되고,
코드 실행 순서는 실행 컨텍스트 스택으로 관리된다.
자바스크립트는 실행 컨텍스트가 활성화되는 시점에 다음과 같은 현상이 발생한다.
호이스팅이 발생한다(선언된 변수를 위로 끌어올린다)
외부 환경 정보를 구성한다.
this 값을 설정한다.
실행 컨텍스트 스택
코드의 실행 순서를 스택으로 관리한다. 소스코드가 평가되면 실행 컨텍스트가 생성되고 실행 컨텍스트 스택의 최상위에 쌓인다.
실행 컨텍스트 최상위에 존재하는 실행 컨텍스트는 언제나 현재 실행 중인 코드의 실행 컨텍스트다.
따라서, 최상위의 실행 컨텍스트를 실행 중인 실행 컨텍스트라 부른다.
렉시컬 환경
식별자와 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 기록하는 자료구조. -> 스코프와 식별자를 관리
실행 컨텍스트를 구성하는 컴포넌트다.
컨텍스트의 4가지 원칙
먼저 전역 컨텍스트 하나를 생성 후, 함수 호출 시마다 컨텍스트가 생긴다.
컨텍스트 생성 시 컨텍스트 안에 변수 객체(arguments, variable), scope chain, this가 생성된다.
컨텍스트 생성 후 함수가 실행되는데, 사용되는 변수들은 변수 객체 안에서 찾고, 안에 값이 없다면 스코프 체인을 따라 위로 올라가면서 찾는다.
함수 실행이 마무리되면 해당 컨텍스트는 사라진다. (클로저 제외) 페이지가 종료되면 전역 컨텍스트가 사라진다.
전역 컨텍스트
전역 컨텍스트가 생성 된 후 2번째 원칙에 따라 변수객체, scope chain, this가 들어온다.
전역 컨텍스트에는 arguments가 없고,
variable은 해당 스코프의 변수들이다. 위 예제에서 name, wow, say가 variable에 해당한다.
scope chain은 자신과 상위 스코프들의 변수 객체를 의미한다. 전역 컨텍스트에서는 자기 자신인 전역 변수 객체만 존재한다.
this는 따로 설정되어 있지 않으면 window다.
이걸 객체 형식으로 표현해보면,
함수 컨텍스트
(7)번에서 say()
를 호출하면 새로운 say 함수 컨텍스트가 생성된다.
arguments는 없고,
variable은 name 뿐이다.
scope chain은 say 변수객체와 상위의 전역 변수객체다.
this는 따로 설정해준 적이 없으니까 window다.
이제 (10)번에서 wow()
함수 컨텍스트가 생성된다.
arguments는 word = 'hello'고,
scope chain은 wow 스코프와 전역 스코프다.
실제 엔진 동작 과정
위에서는 전체적인 흐름만 알아보기 위해 간소하게 설명했다. 실제 엔진 동작 과정을 자세하게 다뤄볼 것이다.
위 예제의 전체적인 흐름은 다음과 같다.
전역 객체 생성
전역 코드 평가
전역 코드 실행
foo 함수 코드 평가
foo 함수 코드 실행
bar 함수 코드 평가
bar 함수 코드 실행
bar 함수 코드 실행 종료
foo 함수 코드 실행 종료
전역 코드 실행 종료
1. 전역 객체 생성
전역 객체는 전역 코드가 평가되기 이전에 생성된다.
빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체로 구성되며, 동작 환경에 따라 클라이언트 사이드 Web API((DOM, BOM, XMLHttpRequest 등) 또는 특정 환경을 위한 호스트 객체를 포함한다.
전역 객체도 Object.prototype
을 상속 받는다. 즉 전역 객체도 프로토타입 체인의 일원이다.
빌트인 객체 브라우저의 자바스크립트 엔진에 내장되어 사용자의 환경에 상관 없이 즉시 사용할 수 있는 코드를 의미한다 ex) Number, String, Boolean, Array, Math, Date, JSON, RegExp
2. 전역 코드 평가
전역 코드 평가는 다음과 같은 순서로 진행된다.
전역 실행 컨텍스트 생성
전역 렉시컬 환경 생성
전역 환경 레코드 생성
객체 환경 레코드 생성
선언적 환경 레코드 생성
this 바인딩
외부 렉시컬 환경에 대한 참조 결정
1) 전역 실행 컨텍스트 생성
먼저 비어있는 전역 실행 컨텍스트를 생성하여 컨텍스트 스택에 푸시한다. 이때 실행 컨텍스트 최상위는 실행 중인 컨텍스트가 된다.
2) 전역 렉시컬 환경 생성
전역 렉시컬 환경Global Lexical Environment
을 생성하고 전역 실행 컨텍스트에 바인딩 한다.
2.1) 전역 환경 레코드 생성
전역 변수를 관리하는 전역 스코프, 전역 객체의 빌트인 전역 프로퍼티, 빌트인 전역 함수, 표준 빌트인 객체를 제공한다.
전역 환경 레코드는 객체 환경 레코드와 선언적 환경 레코드로 구성되어 있다.
객체 환경 레코드: var 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수, 빌트인 전역 함수, 표준 빌트인 객체를 관리
선언적 환경 레코드: let, const 키워드로 선언한 전역 변수를 관리한다.
2.1.1) 객체 환경 레코드 생성
var 키워드로 선언한 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 환경 레코드의 객체 환경 레코드에 연결된 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 된다.
2.1.2) 선언적 환경 레코드 생성
let, const키워드
로 선언한 전역 변수는 전역 객체의 프로퍼티가 되지 않고 선언적 환경 레코드 존재한다.
2.2) this 바인딩
전역 환경 레코드의 [[GlobalThisValue]]
내부 슬롯에 this가 바인딩
된다.
참고로 전역 환경 레코드를 구성하는 객체 환경 레코드와 선언적 환경 레코드에는 this바인딩
이 없다. this바인딩
은 전역 환경 레코드와 함수 환경 레코드에만 존재한다.
2.3) 외부 렉시컬 환경에 대한 참조 결정
현재 평가 중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경, 즉 상위 스코프를 가리킨다.
3. 전역 코드 실행
전역 코드가 순차적으로 실행 된다.
식별자 결정을 위해 실행 중인 실행 컨텍스트에서 식별자를 검색한다.
없으면 상위 스코프로 이동하여 식별자를 검색한다.
4. foo 함수 코드 평가
이제 foo
함수가 호출되면 전역 코드의 실행이 중단되고 제어권이 foo함수 내부
로 이동한다. 그리고 함수 코드를 평가하기 시작한다.
함수 실행 컨텍스트 생성:
foo함수
실행 컨텍스트를 생성하고 실행 컨텍스트 스택에 푸시된다.함수 렉시컬 환경 생성:
foo함수
렉시컬 환경을 생성하고foo함수
실행 컨텍스트에 바인딩(연결)한다.함수 환경 레코드 생성: 매개변수,
arguments객체
, 함수 내부에서 선언한 지역 변수와 중첩 함수를 등록하고 관리한다.this 바인딩:
함수 환경 레코드의
[[ThisValue]]
내부 슬롯에this가 바인딩
된다.foo함수
는 일반 함수로 호출되었으므로this는 전역 객체
를 가리킨다.
외부 렉시컬 환경에 대한 참조 결정:
foo함수
는 전역 코드에 정의된 함수이기 때문에 외부 렉시컬 환경 참조에는 전역 렉시컬 환경의 참조가 할당된다.
5. foo 함수 코드 실행
이제 foo 함수를 실행한다.
6. bar 함수 코드 평가
foo 함수와 마찬가지다.
7. bar 함수 코드 실행
여기서는 console
이 출력된다.
1. console 식별자 검색
console
식별자를 현재 실행중인 실행 컨텍스트의 렉시컬 환경에서부터 시작해 외부 렉시컬 환경에 대한 참조로 이어서 검색하기 시작한다.
console
식별자는 bar 실행 컨텍스트에는 없으니 외부 렉시컬 환경을 따라가 foo 함수의 렉시컬 환경을 확인하고 거기에도 없으니 전역 렉시컬 환경으로 이동하여 검색한다.
전역 렉시컬 환경은 객체 환경 레코드와 선언적 환경 레코드로 나뉘는데 그중 객체 환경 레코드의 BindingObject에서 conole
식별자를 찾을 수 있다.
2. log 메서드 검색 -> 3. 표현식 a + b + x + y + z 평가 -> 4. console.log() 메서드 호출
8. bar 함수 코드 실행 종료
실행 컨텍스트 스택에서 bar함수 실행 컨텍스트가 팝 되어 제거 되며 foo실행 컨텍스트
가 실행중 컨텍스트
가 된다.
9. foo 함수 코드 실행 종료
foo함수도 더이상 실행할 코드가 없으므로 foo함수 코드의 실행도 종료
된다. 이때 실행 컨텍스트 스택에서 foo함수 실행 컨텍스트가 팝 되어 제거되고 전역 실행 컨텍스트
가 실행중인 실행 컨텍스트
가 된다.
10. 전역 코드 실행 종료
전역 실행 컨텍스트도 실행 컨텍스트 스택에서 제거된다.
실행 컨텍스트와 블록 레벨 스코프
var키워드
로 선언된 변수는 오로지 함수의 코드 블록만 지역 스코프로 인정하는 함수 레벨 스코프를 따른다.
하지만 let, const키워드
로 선언한 변수는 모든 코드 블록(함수, if문, for문, while문, try/catch문 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.
if 문이 시작되면 if 문의 코드 블록을 위한 블록 레벨 스코프를 생성해야 한다. 이를 위해 선언적 환경 레코드를 갖는 렉시컬 환경을 새롭게 생성하여 기존의 전역 렉시컬 환경에서 교체한다.
if 문이 종료되면 if 문 코드블록이 실행되기 이전의 렉시컬 환경으로 되돌린다.
호이스팅에 대해서는 다음에 자세하게 다루겠다.
참고
모던 자바스크립트 Deep Dive 23장 - 실행 컨텍스트
Last updated