실행 컨텍스트(execution context)는 자바스크립트의 동작 원리를 담고 있는 핵심 개념이다.
ECMAScript사양은 소스코드를 4가지 타입으로 구분한다.
각 소스코드들은 코드 평가를 통해 실행컨텍스트가 생성된다.
소스코드 -> 코드평가 -> 실행 컨텍스트
전역코드에서는 전역 변수를 관리하기위해 전역스코프를 생성해야한다.
함수코드에서는 지역스코프를 생성하고 지역변수, 매개변수, 인자 객체를 관리해야한다.
eval코드에서는 엄격모드(strict mode)에서 자신만의 독자적인 스코프를 생성한다.
모듈코드에서는 모듈별로 독립적인 모듈 스코프를 생성한다.
위에서 본 바 처럼 소스코드들은 코드 평가를 통해 실행컨텍스트가 실행된다.
var x;
x = 1;
위의 코드를 실행 시킬때 자바스크립트 엔진은 2개의 과정을 나누어 처리한다.
먼저 소스코드 평가 과정에서 선언문을 먼저 실행한다. 이때 생성된 식별자 x는 실행 컨텍스트가 관리하는 스코프에 등록되고 undefined로 초기화한다. 여기까지가 소스코드 평가 과정이고 평과 과정이 끝나면
두번째로 소스코드의 실행, 변수할당문 x = 1이 실행된다. 해당 1을 할당시키기전에 x가 소스코드의 평가를통해 선언된 변수인지를 확인해야한다.
이때 위의 소스코드 평가 과정에서 x는 실행컨텍스트가 관리하는 스코프에 등록되었기때문에 x는 선언된 변수임을 확인하고 1이라는 값을 할당한 후 할당결과를 실행컨텍스트에 등록하여 관리한다.
const x = 1;
const y = 2;
function add(num){
const x = 10;
const y = 20;
console.log(num + x + y);
}
add(100);
console.log(x + y);
위 코드를 보면 전역변수 const x,y 와 함수 내부의 지역변수 const x,y가 있는것을 볼 수 있다.
전역변수는 전역코드에서, 지역변수는 함수코드에서 평가와 실행이 이루어지는데 이 차이를 알아보자.
먼저 전역 코드를 실행하기에 앞서 전역 코드 평가과정을 거치며 전역코드를 실행시키기 위한 준비를 한다. 소스코드 평과 과정에서는 선언문이 먼저 실행된다. 그러므로 변수선언문과 함수선언문이 먼저 실행되고, 실행컨텍스트가 관리하는 전역 스코프에 등록된다.
소스코드 평가 과정이 끝나면 런타임이 시작되어 전역 코드가 순차적으로 실행된다. 이때 전역 변수에 값이 할당되고 함수가 호출된다. 함수가 호출되면 순차적으로 실행되던 전역코드의 실행을 일시중단하고 코드 실행 순서를 변경하여 함수 내부로 진입한다.
위의 전역 코드 실행 도중 함수가 호출될 경우 코드 실행 순서가 변경되어 함수내부로 진입하고 함수내부 문들을 실행하기에 앞서. 함수 소스코드 평가 과정을 거쳐 함수를 코드실행을 할 준비를 한다. 이때 매개변수와 지역변수선언문들이 먼저 실행되고, 그 결과 생성된 변수들이 실행컨텍스트가 관리하는 지역스코프에 등록된다.
평가 과정이 끝나면 런타임되어 함수 코드들이 실행되고, 매개변수와 지역변수에 값이 할당된다. 그 후 메서드들을 실행 시키는데(위에서는 console.log메소드) 이때 스코프 체인을 통하여 지역스코프의 상위스코프인 전역스코프에 연결되어 전역스코프를통해 console.log메소드를 찾게되어 실행하게된다.
위와같이 코드들이 실행되려면 스코프, 식별자, 코드실행순서 등의 관리가 필요한데 이때 이 모든것을 관리하는것이 실행 컨텍스트이다. 즉, 소스코드를 실행하는데 필요한 환경을 제공하고 코드의 실행결과를 실제로 관리하는 영역이다.
실행 컨텍스트는 스택형식(FILO)으로 전역코드와 함수코드의 평가 및 실행이 될때 스택형식으로 실행된다. 이를 슬행 컨텍스트 스택이라고 한다. 위의 코드가 실행 컨텍스트로 실행되면 스택순으로
이런식으로 스택형식으로 실행된다. 이로써 알 수 있는 사실은 실행 컨텍스트 스택의 최상위에 존재하는 실행 컨텍스트가 현재 실행중인 코드의 실행 컨텍스트라는것이다. 그리고 그것을 실행중인 실행컨텍스트(running execution context)라고 한다.
렉시컬 환경은 식별자와 식별자에 바인딩 된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구로로 실행컨텍스트를 구성하는 컴포넌트이다. 실행컨텍스트 스택이 실행순서를 관리한다고하면 렉시컬환경은 스코프와 식별자를 관리한다.
우리는 위에서 실행컨텍스트가 관리하는 스코프에 등록이 되었다고 했는데 이는 곧 스코프를 구분하여 식별자를 등록하고 관리하는 저장소역활을 하는 렉시컬 스코프의 실체이다.
렉시컬 환경은 두개의 컴포넌트로 구성된다.
전역 객체는 전역코드가 평가되기 이전에 생성된다. 그리고 전역객체는 Object.prototype을 상속받는다.
소스코드가 로드되면 자바스크립트 엔진이 전역코드 평가를 한다. 이때 실행컨텍스트 스택 형식으로 FILO로 진행된다.
2.1 전역실행 컨텍스트 생성
2.2 전역렉시컬 환경 생성
2.3 this바인딩
2.4 외부렉시컬 환경에 대한 참조 결정
이후 전역코드들이 순차적으로 실행된다. 그리고 변수들이 할당되고 함수역시 호출된다. 이 때 전역변수에도 x라는 변수가있을수있고, 지역변수에도 x라는 변수가 있을 수 있기에 어느 스코프의 식별자를 참조하면 되는지 결정할 필요가 있는데 이를 식별자 결정이라고한다. 식별자 결정을 하기위해 식별자를 검색할 때는 실행중인 실행 컨텍스트에서 식별자를 검색한다.
함수가 있을경우 전역코드 실행을 중지하고 함수로들어가 함수내부의 코드들을 평가 후 실행한다. 함수의 스코프는 함수를 어디서 호출했는지가 아니라 어디서 정의 했는지에 따라 상위 스코프를 결정한다.
함수 내부의 코드평가 및 실행이 끝나면 함수에서 빠져나와 마저 전역코드를 실행하고 모든 코드들을 실행하게되면 실행이종료되고 실행컨텍스트 스텍에도 모두 팝이되어 실행컨텍스트 스택에 아무것도 남지않게된다.
var키워드는 함수의 코드블록만 지역 스코프로 인정하는 함수 레벨 스코프를 따른다.
let,const는 모든 코드블록을 지역스코프로 인정하는 블록 레벨 스코프를 따른다.
블록 레벨 스코프는 실행될때 코드블록을 위한 새로운 렉시컬 환경을 생성한다. for문에 의한 반복 역시 블록 내에서 반복해서 새로운 렉시컬 환경을 생성한다. 이때 for문의 상위 스코프는 코드블록이 반복해서 실행되더라도 값을 유지해야하기때문에 반복될때마다 독립적인 렉시컬환경을 생성하여 식별자 값을 유지시켜준다.
(이는 다음 장 24장 클로저에 가서 자세히 살펴보도록 하자)