목차
실행 컨텍스트란?
실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체로, 실행 컨텍스트를 이해하는 것은 자바스크립트 엔진이 외부 환경 정보를 구성하고, hoisting, this 등 동작을 수행하는 데, 이에 대한 동작원리를 담고 있는 핵심 개념입니다.
위에서 말한 실행에 필요한 정보들로는 아래와 같은 것들이 있습니다.
- 변수 : 전역변수, 지역변수, 매개변수, 프로퍼티
- 함수 선언
- 변수의 유효범위 (Scope)
- this
이와 같이 동일한 환경에서 실행에 필요한 정보를 모아서 컨텍스트를 구성하고, 이를 콜 스택에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장합니다. 여기서 말하는 "동일한 환경", 즉 하나의 실행 컨텍스트를 구성할 수 있는 방법으로 전역공간, eval 함수, 함수 등이 있습니다. 자동으로 생성되는 전역공간과 사용을 지양하는 eval을 제외하면 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것뿐입니다. 함수를 실행할 때의 예제를 살펴봅시다.
// 1
var a=1;
function outer() {
function inner() {
console.log(a); // undefined
var a = 3;
}
inner(); // 2
console.log(a);
}
outer(); // 3
console.log(a);
처음 자바스크립트 코드를 실행하는 순간(1) 전역 컨텍스트가 콜 스택에 담깁니다. 콜 스택에는 전역 컨텍스트 외에는 아무것도 없으므로 전역 컨텍스트와 관련된 코드들을 순차로 진행하다가 (3)에서 outer 함수를 호출하면 outer에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성한 후 콜 스택에 담습니다. 콜 스택의 맨 위에 outer 실행 컨텍스트가 놓인 상태가 됐으므로 전역 컨텍스트와 관련된 코드들의 실행은 일시중단하고 outer 실행 컨텍스트 즉, outer 함수 내부의 코드들을 순차로 실행합니다. 마찬가지로 (2) inner함수도 순서대로 진행됩니다. inner함수가 종료되면 이전에 중단되었던(함수 호출) 다음 줄부터 -> outer 함수 -> 전역 컨텍스트 순으로 종료됩니다.
위에서 한번 실행할 때 수집하는 정보들을 객체에 담는다고 했는데, 이 담기는 정보들은 정확히 아래와 같이 나눌 수 있습니다.
- VariableEnvironment
- LexicalEnvironment
- ThisBinding
VariableEnvironment
VariableEnvironment는 현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보, 선언 시점의 LexicalEnvironment의 스냅샷으로, 변경사항은 반영되지 않습니다. (최초 실행 시의 스냅샷을 유지한다) 스냅샷은 실행 컨텍스트가 처음 생성될 때의 변수 상태(어떤 변수가 선언되어 있고, 초기값은 무엇인지 등)를 기억한다를 의미합니다.
VariableEnvironment : environmentRecord, outerEnvironmentReference
LexicalEnvironment : environmentRecord, outerEnvironmentReference
실행 컨텍스트를 생성할 때 VariableEnvironment에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LexicalEnvironment를 만들고, 이후에는 LexicalEnvironment에서 주로 활용합니다.
LexicalEnvironment
LexicalEnvironment는 처음에는 VariableEnvironment와 같지만 변경 사항이 실시간으로 반영됩니다.
environmentRecord와 호이스팅
environmentRecord에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 코드 순서대로 저장됩니다. 컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우 그 함수 자체, var로 선언된 변수의 식별자 등이 식별자에 해당합니다.
변수 정보를 수집하는 과정을 모두 마쳤더라도 아직 실행 컨텍스트가 관여할 코드들은 실행되기 전의 상태입니다. 컨텍스트가 실행되기 전이지만 자바스크립트 엔진은 이미 변수 수집을 마쳤고, 이는 "자바스크립트 엔진은 식별자들을 최상단으로 끌어올려놓은(실제로 끌어올리지는 않지만) 다음 실제 코드를 실행한다." 라고 간주해도 될 것 같습니다. 이렇게 끌어올린다를 호이스팅 이라고 합니다. 변수 정보를 수집하는 과정을 이해하기 쉬운 방법으로 대체한 가상의 개념입니다.
호이스팅 규칙
function a (x) { // 수집 대상 1 (매개변수)
console.log(x); // (1)
var x; // 수집 대상 2 (변수 선언)
console.log(x); // (2)
var x = 2; // 수집 대상 3 (변수 선언)
console.log(x); // (3)
}
a(1);
위 예시 코드에서 결과를 예측해보면 1, undefined, 2 가 출력이 될 것 같습니다. 이는 호이스팅이 적용되지 않았을 때의 결과이고 실제로는 호이스팅이 적용되어서 1,1,2가 출력됩니다. 이 적용 과정을 코드로 살펴봅시다.
a(1) 에서 함수를 호출할 때 함수 내부를 살펴보면 함수 안에서 변수를 선언한 것과 같아 보이기에 전달한 값을 함수 안에서 선언하는 것으로 바꿔봅시다.
function a (x) {
var x = 1; // 수집 대상 1 (매개변수)
console.log(x); // (1)
var x; // 수집 대상 2 (변수 선언)
console.log(x); // (2)
var x = 2; // 수집 대상 3 (변수 선언)
console.log(x); // (3)
}
a();
environmentRecord는 현재 실행될 컨텍스트의 코드에서 어떤 식별자들이 있는지에만 관심이 있고, 각 식별자에 어떤 값이 할당될 것인지에는 관심이 없습니다. 따라서 변수를 호이스팅할 때 변수명만 끌어올립니다. 이 과정을 코드로 확인해봅시다.
function a (x) {
var x; // 수집 대상 1의 선언 부분
var x; // 수집 대상 2의 선언 부분
var x; // 수집 대상 3의 선언 부분
x=1; // 수집 대상 1의 할당 부분
console.log(x); // (1)
console.log(x); // (2)
x = 2; // 수집 대상 3의 할당 부분
console.log(x); // (3)
}
a();
위 코드가 호이스팅을 마친 상태이고, 그렇기에 이 상태에서 코드를 실행하면 1,1,2가 출력이 되는 것입니다. 이번에는 변수가 아닌 함수의 호이스팅에 대해서 살펴봅시다.
function a() {
console.log(b); // (1)
var b = 'bbb'; // 수집 대상 1 (변수 선언)
console.log(b); // (2)
function b() {} //수집 대상 2 (함수 선언)
console.log(b); // (3)
}
a()
위 코드도 실행 결과를 먼저 예측해보면 undefined, bbb, function b() {} 가 나올 것 같습니다. 위 코드가 호이스팅이 적용될 때 어떻게 동작하는지 봅시다.
function a() {
var b;
function b() {} // 함수 선언은 전체를 끌어올립니다.
console.log(b); // (1)
b = 'bbb';
console.log(b); // (2)
console.log(b); // (3)
}
a()
여기까지만 보면 여전히 헷갈릴 수 있지만, 호이스팅이 끝난 상태에서의 함수 선언문은 함수명으로 선언한 변수에 함수를 할당한 것처럼 여길 수 있습니다.
function a() {
var b;
var b = function b() {} // 함수 선언은 전체를 끌어올립니다.
console.log(b); // (1)
b = 'bbb';
console.log(b); // (2)
console.log(b); // (3)
}
a()
이제 호이스팅을 마쳤습니다. 코드 결과는 function b() {}, bbb, bbb 가 출력됩니다.
참고자료
- 코어 자바스크립트 책
- https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8
[JS] 📚 자바스크립트 실행 컨텍스트 원리
실행 컨텍스트 실행 컨텍스트(Execution Context)는 scope, hoisting, this, function, closure 등의 동작원리를 담고 있는 자바스크립트의 핵심원리이다. 실행 컨텍스트를 바로 이해하지 못하면 코드 독해가
inpa.tistory.com
'JavaScript' 카테고리의 다른 글
자바스크립트의 데이터 타입 (0) | 2025.07.30 |
---|---|
AJAX (0) | 2025.07.26 |
자바스크립트 이벤트루프 (1) | 2025.07.26 |
자바스크립트에서의 this (0) | 2025.07.19 |
자바스크립트의 렉시컬 스코프(Lexical Scope) (0) | 2025.07.19 |