실행 컨텍스트
실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체입니다. 자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고(호이스팅), 외부 환경 정보를 구성하고, this 값을 설정하는 등의 동작을 수행합니다.
하나의 실행 컨텍스트를 구성할 수 있는 방법
전역 공간, eval() 함수, 함수 등이 있습니다. 자동으로 생성되는 전역공간과 eval을 제외하면 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것입니다. (ES6에서는 블록에 의해서도 새로운 실행 컨텍스트가 생성됩니다)
실행 컨텍스트는 어떻게 구성되어 있을까?
VariableEnvironment
environmentRecord(snapshot)
outerEnvironmentReference(snapshot)
LexicalEnvironment
environmentRecord
outerEnvironmentReference
ThisBinding
VariableEnvironment와 LexicalEnvironment의 차이점
VariableEnvironment에 담기는 내용은 LexicalEnvironment와 같지만 최초 실행 시의 스냅샷을 유지한다는 점이 다릅니다. 실행 컨텍스트를 생성할 때 VariableEnvironment에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LexicalEnvironment를 만들고, 이후에는 LexicalEnvironment를 주로 활용하게 됩니다.
environmentRecord
environmentRecord에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장됩니다. 컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우 그 함수 자체, var로 선언된 변수의 식별자 등이 식별자에 해당합니다. 컨텍스트 내부 전체를 처음부터 끝까지 쭉 훑어나가며 순서대로 수집합니다.
호이스팅
코드를 실행하기 전 변수의 식별자와 함수 선언문을 스코프의 최상단으로 끌어 올리는 것과 같은 현상입니다. environmentRecord에서 변수 정보를 모두 수집했더라도 아직 실행 컨텍스트가 관여할 코드들은 실행되기 전의 상태입니다. 코드가 실행되기 전부터 이미 해당 환경에 속한 코드의 변수명들을 모두 알고 있게 되는 셈인데, 이는 식별자들이 코드의 최상단으로 끌어 올려진 상태와 비슷하게 해석할 수도 있습니다. 이를 호이스팅이라 하는데 변수 정보를 수집하는 과정을 이해하기 쉬운 방법으로 대체한 가상의 개념입니다.
함수 선언문과 함수 표현식
둘 모두 함수를 새롭게 정의할 때 쓰이는 방식입니다. 함수 선언문은 function 정의부만 존재하고 별도의 할당 명령이 없는 것을 의미하고, 반대로 함수 표현식은 정의한 function을 별도의 변수에 할당하는 것을 말합니다. 함수명을 정의한 함수 표현식을 ‘기명 함수 표현식’, 정의하지 않은 것을 ‘익명 함수 표현식’이라고 부르기도 하는데 일반적으로 함수 표현식은 익명 함수 표현식을 말합니다.
// 함수 선언문. 함수명 a가 곧 변수명.
function a () { /* ... */ }
a(); // 실행 OK.
// (익명) 함수 표현식. 변수명 b가 곧 함수명.
var b = function () { /* ... */ }
b(); // 실행 OK.
// 기명 함수 표현식. 변수명은 c, 함수명은 d.
var c = function d () { /* ... */ }
c(); // 실행 OK.
d(); // 에러!
함수 선언문과 함수 표현식의 차이점
함수 선언문은 전체를 호이스팅하고 함수 표현식은 변수 선언부만 끌어올립니다.
스코프, 스코프 체인
스코프란 식별자에 대한 유효범위입니다. 자바스크립트의 경우 ES5까지는 전역공간을 제외하면 오직 함수에 의해서만 스코프가 생성됩니다. 이러한 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것을 스코프체인이라 합니다. 그리고 이를 가능케 하는 것이 바로 outerEnvironmentReference입니다.
스코프체인과 실행 컨텍스트
outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조합니다. 선언 시점의 LexicalEnvironment를 계속 찾아 올라가면 마지막엔 전역 컨텍스트의 LexicalEnvironment가 있을 것입니다. 또한 각 outerEnvironmentReference는 오직 자신이 선언된 시점의 LexicalEnvironment만 참조하고 있으므로 가장 가까운 요소부터 차례대로만 접근할 수 있고 다른 순서로 접근하는 것은 불가능할 것입니다. 이런 구조적 특성 덕분에 여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능하게 됩니다.