728x90
반응형
SMALL

실행 컨텍스트 (Execution Context) 완벽 가이드
실행 컨텍스트란?
자바스크립트 코드가 실행되는 환경.
코드가 실행되기 위해 필요한 모든 정보(변수, 함수, this 등)를 담고 있는 객체.
실행 컨텍스트의 종류
// 1. 전역 실행 컨텍스트 - 코드 시작 시 생성
var globalVar = '전역';
// 2. 함수 실행 컨텍스트 - 함수 호출 시 생성
function foo() {
var localVar = '지역';
}
foo();
// 3. eval 실행 컨텍스트 - eval() 호출 시 (거의 안 씀)
| 종류 | 생성 시점 | 개수 |
| 전역 | 코드 시작 | 1개 |
| 함수 | 함수 호출마다 | 여러 개 |
| eval | eval 호출 | 거의 안 씀 |
콜 스택 (Call Stack)
실행 컨텍스트가 쌓이는 자료구조. LIFO(Last In First Out) 방식.
function first() {
console.log('first');
second();
}
function second() {
console.log('second');
third();
}
function third() {
console.log('third');
}
first();
콜 스택 변화:
1. 코드 시작
┌─────────┐
│ 전역 │
└─────────┘
2. first() 호출
┌─────────┐
│ first │
├─────────┤
│ 전역 │
└─────────┘
3. second() 호출
┌─────────┐
│ second │
├─────────┤
│ first │
├─────────┤
│ 전역 │
└─────────┘
4. third() 호출
┌─────────┐
│ third │
├─────────┤
│ second │
├─────────┤
│ first │
├─────────┤
│ 전역 │
└─────────┘
5. third() 종료 → 스택에서 제거
6. second() 종료 → 스택에서 제거
7. first() 종료 → 스택에서 제거
8. 전역만 남음
실행 컨텍스트 구조
┌──────────────────────────────────────────────────────┐
│ 실행 컨텍스트 (Execution Context) │
├──────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 1. 렉시컬 환경 (Lexical Environment) │ │
│ │ • let, const, 함수 선언문 관리 │ │
│ │ • 블록 스코프 지원 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 2. 변수 환경 (Variable Environment) │ │
│ │ • var 관리 │ │
│ │ • 함수 스코프만 인식 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 3. This 바인딩 (This Binding) │ │
│ │ • this 값 결정 │ │
│ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 렉시컬 환경 / 변수 환경 │
├─────────────────────────────────────┤
│ │
│ ┌─────────────────────────────┐ │
│ │ 환경 레코드 │ │
│ │ (Environment Record) │ │
│ │ • 식별자와 값의 바인딩 저장 │ │
│ └─────────────────────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ 외부 환경 참조 │ │
│ │ (Outer Environment Ref) │ │
│ │ • 상위 스코프 참조 │ │
│ │ • 스코프 체인, 클로저의 핵심 │ │
│ └─────────────────────────────┘ │
│ │
└─────────────────────────────────────┘
렉시컬 환경 (Lexical Environment)
구성 요소
┌─ 렉시컬 환경 ─────────────────────┐
│ │
│ 환경 레코드 (Environment Record) │
│ - 현재 스코프의 변수, 함수 저장 │
│ │
│ 외부 환경 참조 (Outer Reference) │
│ - 상위 스코프 참조 (스코프 체인) │
│ │
└───────────────────────────────────┘
환경 레코드 종류
// 1. 선언적 환경 레코드 - 함수, 변수
function foo() {
let a = 1; // 선언적 환경 레코드에 저장
const b = 2;
}
// 2. 객체 환경 레코드 - 전역 객체 (window/global)
var globalVar = '전역'; // window.globalVar로 접근 가능
| 환경 레코드 | 저장 대상 | 특징 |
| 선언적 | let, const, 함수, 매개변수 | 일반적인 변수 저장 |
| 객체 | var (전역), 전역 함수 | 전역 객체의 프로퍼티가 됨 |
변수 환경 (Variable Environment)
var만 저장하는 공간.
렉시컬 환경과 구조는 동일하지만 var 전용.
function example() {
var a = 1; // 변수 환경
let b = 2; // 렉시컬 환경
const c = 3; // 렉시컬 환경
}
왜 분리했을까?
블록 스코프 지원 때문
function test() {
var a = 1;
let b = 1;
if (true) {
var a = 2; // 같은 변수 환경 → 덮어씀
let b = 2; // 새로운 렉시컬 환경 → 별개
}
console.log(a); // 2 (덮어써짐)
console.log(b); // 1 (블록 밖은 그대로)
}
실무에서는 var를 안 쓰니까 렉시컬 환경만 신경쓰면 됨.
this 바인딩
실행 컨텍스트 생성 시 this가 결정됨.
// 전역 컨텍스트
console.log(this); // window (브라우저) / global (Node.js)
// 함수 컨텍스트 - 호출 방식에 따라 다름
function foo() {
console.log(this);
}
foo(); // window (일반 호출)
obj.foo(); // obj (메서드 호출)
new foo(); // 새 인스턴스 (생성자 호출)
foo.call(obj); // obj (명시적 바인딩)
| 호출 방식 | this |
| 일반 호출 | window (strict mode: undefined) |
| 메서드 호출 | 호출한 객체 |
| 생성자 호출 | 새 인스턴스 |
| call/apply/bind | 명시한 객체 |
| 화살표 함수 | 상위 스코프의 this |
실행 컨텍스트 생성 과정
1단계: 생성 단계 (Creation Phase)
function foo(a) {
var b = 10;
function bar() {}
}
foo(5);
생성 단계에서 실행 컨텍스트가 만들어짐:
foo 실행 컨텍스트 (생성 단계)
┌─────────────────────────────┐
│ 렉시컬 환경 │
│ - a: 5 (매개변수) │
│ - bar: function (함수 전체)│
│ - 외부 참조: 전역 │
├─────────────────────────────┤
│ 변수 환경 │
│ - b: undefined (var 호이스팅)│
├─────────────────────────────┤
│ this: window │
└─────────────────────────────┘
2단계: 실행 단계 (Execution Phase)
코드가 한 줄씩 실행되면서 값이 할당됨:
foo 실행 컨텍스트 (실행 단계)
┌─────────────────────────────┐
│ 변수 환경 │
│ - b: 10 (할당됨) │
└─────────────────────────────┘
호이스팅 (Hoisting)
생성 단계에서 선언이 먼저 처리되기 때문에 발생하는 현상.
호이스팅 시점에 저장되는 것
| 생성 단계 | 실행 단계 | |
| var | undefined로 초기화 | 값 할당 |
| let/const | 초기화 안 됨 (TDZ) | 값 할당 |
| 함수 선언식 | 함수 전체 저장 | - |
| 함수 표현식 | var면 undefined | 함수 할당 |
var 호이스팅
console.log(a); // undefined
var a = 10;
console.log(a); // 10
내부 동작:
// 생성 단계
var a = undefined;
// 실행 단계
console.log(a); // undefined
a = 10;
console.log(a); // 10
let/const와 TDZ
console.log(b); // ❌ ReferenceError
let b = 2;
TDZ(Temporal Dead Zone): 선언은 호이스팅되지만 초기화 전까지 접근 불가한 구간.
코드 시작
│
│ ← TDZ 시작 (b 선언은 인식됨)
│
▼
let b = 2; ← TDZ 끝 (초기화)
│
▼
console.log(b); // 2
함수 선언식 vs 함수 표현식
// 함수 선언식 - 전체가 호이스팅
foo(); // ✅ 'hello'
function foo() {
console.log('hello');
}
// 함수 표현식 - var만 호이스팅
bar(); // ❌ TypeError: bar is not a function
var bar = function() {
console.log('hello');
};
함수 선언식은 생성 단계에서 함수 전체가 저장되어 어디서든 호출 가능.
전체 흐름 예시
var a = 1;
let b = 2;
function foo() {
var c = 3;
let d = 4;
function bar() {
console.log(a, b, c, d);
}
bar();
}
foo();
1. 전역 컨텍스트 생성 (생성 단계)
┌─ 전역 실행 컨텍스트 ─────────────┐
│ 렉시컬 환경 │
│ - b: <uninitialized> (TDZ) │
│ - foo: function │
│ - 외부 참조: null │
├──────────────────────────────────┤
│ 변수 환경 │
│ - a: undefined │
├──────────────────────────────────┤
│ this: window │
└──────────────────────────────────┘
2. 전역 컨텍스트 (실행 단계)
- a = 1
- b = 2
3. foo() 호출 → foo 컨텍스트 생성 (생성 단계)
┌─ foo 실행 컨텍스트 ──────────────┐
│ 렉시컬 환경 │
│ - d: <uninitialized> │
│ - bar: function │
│ - 외부 참조: 전역 │
├──────────────────────────────────┤
│ 변수 환경 │
│ - c: undefined │
└──────────────────────────────────┘
4. foo 컨텍스트 (실행 단계)
- c = 3
- d = 4
5. bar() 호출 → bar 컨텍스트 생성
┌─ bar 실행 컨텍스트 ──────────────┐
│ 렉시컬 환경 │
│ - 외부 참조: foo │
└──────────────────────────────────┘
6. bar에서 변수 찾기 (스코프 체인)
- a: bar에 없음 → foo에 없음 → 전역에서 찾음 (1)
- b: bar에 없음 → foo에 없음 → 전역에서 찾음 (2)
- c: bar에 없음 → foo에서 찾음 (3)
- d: bar에 없음 → foo에서 찾음 (4)
7. bar() 종료 → bar 컨텍스트 제거
8. foo() 종료 → foo 컨텍스트 제거
9. 전역 컨텍스트만 남음
정리
| 개념 | 설명 |
| 실행 컨텍스트 | 코드 실행에 필요한 정보를 담은 환경 |
| 콜 스택 | 실행 컨텍스트가 쌓이는 LIFO 구조 |
| 렉시컬 환경 | let, const, 함수 저장 + 스코프 체인 |
| 변수 환경 | var 저장 (실무에서 거의 안 씀) |
| 생성 단계 | 선언 처리, 호이스팅 발생 |
| 실행 단계 | 코드 실행, 값 할당 |
| 호이스팅 | 생성 단계에서 선언이 먼저 처리되는 현상 |
| TDZ | let/const가 초기화 전 접근 불가한 구간 |
728x90
반응형
LIST
'javascript' 카테고리의 다른 글
| 브라우저 vs Node.js: JavaScript 실행 환경의 차이 (1) | 2026.01.21 |
|---|---|
| JavaScript 실행 방식: 컴파일러 vs 인터프리터 vs JIT (0) | 2026.01.21 |
| [Javascript] XSS(Cross-Site Scripting), CSRF(Cross-Site Request Forgery) (0) | 2024.06.19 |
| [Javascript] at(), slice(), splice() (1) | 2024.05.17 |
| [Javascript] New URL(), New URLSearchParams() (0) | 2024.05.17 |
댓글