728x90
반응형
SMALL

함수 선언문과 실행 컨텍스트: 메모리 관점에서 이해하기
메모리 구조 먼저 이해하기
자바스크립트의 메모리는 크게 세 영역으로 나뉜다.
┌─────────────────────────────────────────────────────┐
│ 메모리 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Stack Memory │ │ Heap Memory │ │
│ │ │ │ │ │
│ │ 원시값, 힙 주소 │ │ 객체, 함수 등 │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 실행 컨텍스트 │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ Lexical Environment │ │
│ │ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Environment Record │ │ │
│ │ │ │ │ │
│ │ │ 식별자 목록 관리 │ │ │
│ │ │ (어떤 식별자가 어디를 가리키는지) │ │
│ │ └─────────────────────────────┘ │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
| 영역 | 역할 |
| Stack Memory | 원시값, 힙 주소 저장 |
| Heap Memory | 객체, 함수 등 참조 타입 저장 |
| Environment Record | 식별자 목록 관리 (이름 → 스택 주소 매핑) |
콜 스택 vs 스택 메모리
둘 다 "스택"이지만 다른 개념이다.
function a() { b(); }
function b() { console.log('hi'); }
a();
┌─────────────────┐
│ b() 컨텍스트 │ ← 나중에 들어오고 먼저 나감
├─────────────────┤
│ a() 컨텍스트 │
├─────────────────┤
│ Global 컨텍스트 │
└─────────────────┘
콜 스택
| 콜 스택 | 스택 메모리 | |
| 저장하는 것 | 실행 컨텍스트 | 원시값, 힙 주소 |
| 역할 | 함수 호출 순서 관리 | 데이터 저장 |
| 정의 | 함수 호출 순서를 관리하는 **자료구조** | 값을 저장하는 **메모리 영역** |
함수 선언문의 실행 컨텍스트 생성 과정
function add(a, b) {
return a + b;
}
add(1, 2);
1단계: 실행 컨텍스트 생성
코드 실행 전에 자바스크립트 엔진이 실행 컨텍스트를 생성한다.
2단계: 함수 선언문 처리 (생성 단계)
2-1. 힙 메모리에 함수 객체 생성
┌─────────────────────────────┐
│ Heap Memory │
│ │
│ ┌────────────────────────┐ │
│ │ Function 객체 │ │
│ │ 주소: 0x001 │ │
│ │ │ │
│ │ - 코드: return a + b │ │
│ │ - [[Scope]] │ │
│ │ - name: "add" │ │
│ └────────────────────────┘ │
└─────────────────────────────┘
2-2. 스택 메모리에 힙 주소 저장
┌─────────────────┐ ┌─────────────────┐
│ Stack Memory │ │ Heap Memory │
│ │ │ │
│ 0x001 (힙 주소) │──────────▶│ Function 객체 │
└─────────────────┘ └─────────────────┘
2-3. Environment Record에 식별자 등록
자바스크립트 엔진이 함수 이름과 동일한 식별자 add를 암묵적으로 생성한다.
┌─────────────────────────────────────────────────────┐
│ 메모리 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Stack Memory │ │ Heap Memory │ │
│ │ │ │ │ │
│ │ 0x001 ─────────────────▶ Function 객체 │ │
│ └─────────────────┘ │ 주소: 0x001 │ │
│ ▲ └─────────────────┘ │
└─────────│───────────────────────────────────────────┘
│
┌─────────│───────────────────────────────────────────┐
│ │ 실행 컨텍스트 │
│ ┌──────│──────────────────────────────┐ │
│ │ Environment Record │ │
│ │ │ │
│ │ add ───────────▶ Stack의 0x001 │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
💡 이 시점에서 이미 add 식별자로 함수 호출이 가능하다. (호이스팅)
3단계: 코드 실행 (실행 단계)
add(1, 2); // 식별자 add → 스택 → 힙의 함수 객체 찾아서 실행
var 변수와의 차이
var x = 10;
생성 단계:
Environment Record
│
│ x ──────▶ undefined (초기화만)
실행 단계:
Environment Record Stack Memory
│
│ x ────────────────▶ 10
핵심 차이
| 함수 선언문 | var 변수 | |
| 생성 단계 | 힙에 객체 + 스택에 주소 + 식별자 바인딩 완료 | 식별자 등록 + undefined 초기화만 |
| 실행 단계 | 이미 완료됨 | 실제 값 할당 |
| 호이스팅 결과 | 호출 가능 | undefined |
add(1, 2); // ✅ 가능 - 생성 단계에서 이미 완료
function add(a, b) { return a + b; }
console.log(x); // undefined - 초기화만 된 상태
var x = 10;
재할당 시 메모리 변화
원시값 재할당
let x = 10;
x = 20;
// 처음
Environment Record Stack Memory
x ──────────────────────▶ 10 (주소: 0x001)
// 재할당 후
Environment Record Stack Memory
x ──────────────────────▶ 20 (주소: 0x002) ← 새 주소
10 (주소: 0x001) ← 가비지 컬렉션 대상
원시값은 불변이라 새 메모리에 값을 만들고, 식별자가 새 주소를 가리킨다.
객체 재할당
let obj = { a: 1 };
obj = { b: 2 };
// 처음
Environment Record Stack Memory Heap Memory
obj ────────────────▶ 0x001 ───────────▶ { a: 1 }
// 재할당 후
Environment Record Stack Memory Heap Memory
obj ────────────────▶ 0x002 ───────────▶ { b: 2 } ← 새 객체
0x001 ───────────▶ { a: 1 } ← 가비지 컬렉션 대상
새 객체가 힙에 생성되고, 스택에 새 주소가 저장되고, 식별자가 새 스택 주소를 가리킨다.
객체 프로퍼티만 수정
let obj = { a: 1 };
obj.a = 100;
// 처음
Environment Record Stack Memory Heap Memory
obj ────────────────▶ 0x001 ───────────▶ { a: 1 }
// 수정 후
Environment Record Stack Memory Heap Memory
obj ────────────────▶ 0x001 ───────────▶ { a: 100 } ← 힙 내용만 변경
식별자, 스택 주소 그대로고 힙 내용만 변경된다.
💡 그래서 const로 선언해도 프로퍼티 수정이 가능하다. const는 식별자의 바인딩(스택 주소)을 못 바꾸게 하는 거지, 힙 내용까지 막는 게 아니다.
728x90
반응형
LIST
'javascript' 카테고리의 다른 글
| 화살표 함수의 this가 정적인 이유 (0) | 2026.01.26 |
|---|---|
| 함수 선언문은 함수이름이 아니라 자바스크립트 엔진이 암묵적으로 만든 식별자로 호출된다 (0) | 2026.01.26 |
| 객체 메서드: 축약형 vs 일반형 차이점 (0) | 2026.01.26 |
| 실행 컨텍스트와 스택 메모리 (0) | 2026.01.25 |
| JavaScript 메모리 구조: 스택과 힙 (0) | 2026.01.25 |
댓글