MoEasy - 자바스크립트 스터디(2주차) - 실행 컨텍스트, 스코프 체인, 렉시컬 환경, 일급 객체, 클로저

연도·2025년 2월 7일

JavaScript, TypeScript

목록 보기
2/8
post-thumbnail

제시된 코드를 보고 코드의 평가 및 실행단계에 따라 실행 컨텍스트, 스코프 체인, 렉시컬 환경이 어떻게 생성되고 제거되는지 그림을 그려가면서 설명하기.

문제 코드

const x = 1;
function foo () {
  const y = 2;
  function bar () {
    const z = 3;
    console.log(x + y + z);
  }
  bar();
}
foo();

코드 평가 및 실행 단계

  1. 코드 평가 단계

자바스크립트 엔진이 코드를 만나면 평가 과정을 통해 실행 컨텍스트를 준비함.

이때 변수/함수 선언을 메모리에 등록함.

전역에 x가 초기화 되지 않았고(const, TDZ), foo는 함수 전체가 등록되었다.

주의할 점은 x는 메모리에 올라가지만 초기화 되지 않았다(TDZ)

foo는 함수 선언이므로 전체 코드가 미리 메모리에 등록됨.

  1. 전역 실행 컨텍스트 활성화

const x = 1 이 실행되고, x에 1이 할당됨!

전역 렉시컬 환경이 완성되었다. foo(function), x(1)

  1. foo() 호출하면 foo 실행 컨텍스트가 생성됨.

환경 레코드 : y는 초기화 되지 않음(const, TDZ), bar는 함수 전체가 등록되었다.

외부 렉시컬 환경 참조 : 전역 렉시컬 환경인 x, foo

foo의 컨텍스트가 활성화되어서 y = 2로 초기화 됨.

  1. bar() 호출하면 bar 실행 컨텍스트가 생성됨.

환경 레코드 : z는 초기화 되지 않음(const, TDZ),

외부 렉시컬 환경 참조 : foo 렉시컬 환경인 y, bar

bar 컨텍스트가 활성화되어서 z = 3으로 초기화 됨.

  1. 콘솔로그 x, y, z 실행

스코프 체인으로 돌아감.

z는 bar 렉시컬 환경에서

y는 foo 렉시컬 환경에서

x는 전역 렉시컬 환경에서

최종 출력은 6!

컨텍스트 소멸 순서는 bar 컨텍스트, foo 컨텍스트가 소멸되고

전역 컨텍스트는 유지가 됌. 앱이 종료될 때 소멸된다.

키워드 정리

실행 컨텍스트

코드 실행 시에 필요한 모든 정보를 담은 틀이다.

변수, 함수, 선언 정보들 저장, 코드 실행 흐름 관리, 생성 시점(전역 코드, 함수 호출)

렉시컬 환경

변수와 함수가 저장되는 장소(스코프의 찐 실체)

환경 레코드 : 실제 변수의 값

외부 렉시컬 환경 참조 : 상위 스코프 참조

스코프 체인

변수 찾기 위한 체인(내부 → 외부 → 전역)

안쪽에서 찾지 못하면 바깥쪽으로 올라감.

렉시컬 환경들의 연결 고리임

최종 정리

자바스크립트는 코드를 평가하는 단계와 실행 단계로 나눠진다. 각 단계마다 실행 컨텍스트가 만들어져 메모리에 저장됨. 변수, 함수 선언은 평가 단계에서 메모리에 올라감. 하지만 let/const는 TDZ로 인해서 초기화 전 접근 시에 에러가 발생함. 함수가 호출될 때마다 새 실행 컨텍스트와 렉시컬 환경이 만들어지고, 외부 렉시컬 환경을 참조해 스코프 체인을 구성한다.

자바스크립트에서의 함수는 일급 객체의 특성을 가지고 있다. 이와 연결하여 클로저 개념에 대해 설명하고 클로저로 구현할 수 있는 개념의 예시를 조사하기

함수의 일급 객체

값처럼 다룰 수 있는 개체.

변수에 저장하고 함수의 인자/반환 값으로 사용 가능한 객체

자바스크립트에서 함수가 일급 객체인 이유

변수에 할당 가능함.

함수의 인자로 전달 가능함.

함수의 반환값으로 사용 가능함.

// 변수에 저장 가능함.
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5

// 인자로 전달이 가능함.
function compute(operation, x, y) {
  return operation(x, y);
}
console.log(compute(add, 5, 7)); // 12

//함수 반환 가능함.
function multiplier(factor) {
  return function (value) {
    return value * factor;
  };
}

const double = multiplier(2);
console.log(double(4)); // 8

클로저

함수와 그 함수가 선언될 당시의 렉시컬 환경의 조합

내부 함수가 외부 함수의 변수를 참조할 때 형성됨.

외부 함수의 실행이 끝나도, 내부 함수는 변수의 참조를 기억함.

function outer(outerVar) {
  return function inner(innerVar) {
    return `Outer: ${outerVar}, Inner: ${innerVar}`;
  };
}

const closureFunc = outer('Hello');
console.log(closureFunc('World')); // Outer: Hello, Inner: World

outerVar는 outer()가 종료되어도 클로저로 기억됨.

closureFunc(’world’) 실행 시에, 외부 변수 + 내부 변수로 모두 접근이 가능하다.

클로저로 구현 가능한 주요 패턴

  1. 상태 유지
function createCounter() {
  let count = 0; // 상태 (private)
  return function () {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
  1. 비공개 변수
function createSecret(secret) {
  return function () {
    return secret;
  };
}

const getSecret = createSecret('Top Secret');
console.log(getSecret()); // Top Secret

외부에서 직접 접근 불가능해야 하는 민감한 데이터 보호

  1. 함수형 프로그래밍 (커링)
function multiply(a) {
  return function (b) {
    return a * b;
  };
}

const double = multiply(2);
console.log(double(5)); // 10

미리 설정된 파라미터로 함수를 생성하고, 유연한 함수 조합.

렉시컬 환경에서 클로저 덕분에 내부에 있는 함수가 전역에 있는 변수를 계속해서 참조할 수 있는 것

최종 정리

자바스크립트에서 함수는 일급 객체로 변수에 저장을 한다. 그리고 인자/반환으로 사용 가능하며, 클로저를 통해서 외부 스코프를 기억하는 기능을 가지게 된다. 이를 통해 상태 관리, 프라이빗 변수, 고차 함수 등 다양한 패턴으로 활용이 가능하게 됨.

profile
Software Engineer

0개의 댓글