실행 컨텍스트 (Execution Context) 완벽 가이드

    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

    댓글