함수 선언문과 실행 컨텍스트: 메모리 관점에서 이해하기

    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

    댓글