# 자바스크립트 비밀스러운 삶: 클로저(Closure) 완전 정복 – 함수가 기억하는 이유와 활용법

*(SEO 키워드: JavaScript 클로저, 함수 기억, 프로그래밍 기초)*

---

# # 서론 – “함수가 왜 기억을 가지고 있을까?”

프로그래밍을 처음 시작한 사람이라면 “함수는 호출될 때마다 새롭게 실행되는 일회용 도구”라고 생각하기 쉽습니다. 그런데 **JavaScript**에서는 함수가 **자신이 선언될 때의 환경을 기억**하고, 그 기억을 바탕으로 나중에 호출될 수 있다는 독특한 특성이 있습니다. 이를 **클로저(Closure)** 라고 부릅니다.

이 개념을 제대로 이해하지 못하면 비동기 처리, 이벤트 핸들링, 모듈화 같은 핵심 기능을 구현할 때 예상치 못한 버그와 성능 저하를 겪게 됩니다. 이번 포스트에서는 **‘Chapter 4: Functions Remember’** 라는 이야기를 통해, 클로저가 어떻게 동작하고, 실무에서 어떻게 활용할 수 있는지 초보자도 쉽게 따라올 수 있도록 단계별로 풀어보겠습니다.

> **예시 이야기** – 비가 억수같이 내리던 어느 날, **Timothy**는 우산을 잊고 도서관에 들어섰습니다. 그는 책을 찾으며 “내가 지난번에 읽었던 페이지를 기억하고 있으면 좋겠어” 라는 생각을 했고, 이는 곧 **함수가 기억을 갖는 상황**과 놀라운 유사성을 보여줍니다.

---

# # 본론

## # 1️⃣ 클로저란 무엇인가? – 함수가 환경을 ‘캡처’한다

### # 1-1. 스코프와 렉시컬 스코프

- **스코프**는 변수와 함수가 접근 가능한 범위를 의미합니다.

- **렉시컬(lexical) 스코프**는 함수가 **정의된 위치**에 따라 스코프가 결정됩니다. 즉, 함수 내부에서 외부 변수를 참조하면, 그 변수가 선언된 **외부 환경**을 기억하게 됩니다.

### # 1-2. 클로저의 정의

> **클로저(Closure)** = **함수** + **함수가 선언될 때의 렉시컬 환경**

즉, 함수가 선언된 순간의 **스코프 체인**을 함께 저장해 두는 메커니즘입니다. 이때문에 함수가 **다른 함수 안에서 반환**되더라도, 외부 변수에 계속 접근할 수 있습니다.

### # 1-3. 간단한 예시

```
javascript

function makeCounter() {

  let count = 0;               // 외부 변수

  return function() {         // 내부 함수(클로저)

    count += 1;               // 외부 변수에 접근

    return count;

  };

}

const counter = makeCounter(); // makeCounter의 실행 결과는 클로저

console.log(counter()); // 1

console.log(counter()); // 2

```

위 코드에서 `counter`는 `makeCounter` 내부에서 선언된 `count` 변수를 **계속 기억**하고 있습니다. 이것이 바로 **함수가 기억하는** 메커니즘, 즉 **클로저**입니다.

---

## # 2️⃣ 클로저가 필요한 실제 상황 – 비동기와 이벤트 핸들링

### # 2-1. 타이머와 클로저

```
javascript

for (let i = 1; i <= 5; i++) {

  setTimeout(function() {

    console.log(i); // 1,2,3,4,5 순서대로 출력

  }, i * 1000);

}

```

`setTimeout` 콜백 안에서 `i`를 사용하면, **각 콜백이 실행될 때마다 현재 `i` 값을 기억**합니다. `let`을 사용했기 때문에 블록 스코프가 보장돼 각 반복마다 새로운 `i`가 생성됩니다.

### # 2-2. DOM 이벤트와 클로저

```
javascript

function addButtonListener(id) {

  const button = document.getElementById(id);

  let clickCount = 0; // 버튼마다 별도 카운트

  button.addEventListener('click', function() {

    clickCount++;

    console.log(`버튼 ${id} 클릭 횟수: ${clickCount}`);

  });

}
addButtonListener('btn1');

addButtonListener('btn2');

```

버튼마다 독립적인 `clickCount` 변수를 **클로저**가 기억해 주기 때문에, 서로 간섭 없이 클릭 횟수를 관리할 수 있습니다.

### # 2-3. 비동기 API 호출과 클로저

```
javascript

function fetchUser(id) {

  return fetch(`https://api.example.com/users/${id}`)

    .then(response => response.json())

    .then(user => {

      // 여기서 id는 클로저에 의해 기억됨

      console.log(`User ${id}:`, user.name);

    });

}
fetchUser(42);

```

`then` 체인 안에서 `id`를 사용할 수 있는 이유는 **클로저가 `fetchUser` 실행 시점의 `id` 값을 기억**하기 때문입니다.

---

## # 3️⃣ 클로저 활용 패턴 – 모듈, 데이터 은닉, 커링

### # 3-1. 모듈 패턴 (IIFE)

```
javascript

const CounterModule = (function() {

  let count = 0; // 외부에 노출되지 않음

  return {

    increment: function() { return ++count; },

    decrement: function() { return --count; },

    getCount: function() { return count; }

  };

})();

CounterModule.increment(); // 1

CounterModule.getCount();  // 1

```

즉시 실행 함수(IIFE) 안에서 선언된 `count` 변수는 **클로저**를 통해 외부에 은닉됩니다.

### # 3-2. 데이터 은닉과 프라이버시

클로저를 이용하면 객체 내부에 **프라이빗 변수**를 만들 수 있습니다.

```
javascript

function createBankAccount(initialBalance) {

  let balance = initialBalance; // 프라이빗 변수

  return {

    deposit: amount => { balance += amount; return balance; },

    withdraw: amount => {

      if (amount > balance) throw new Error('잔액 부족');

      balance -= amount;

      return balance;

    },

    getBalance: () => balance

  };

}
const account = createBankAccount(1000);

account.deposit(500); // 1500

account.getBalance(); // 1500

```

### # 3-3. 커링(Currying)과 부분 적용

```
javascript

function multiply(a) {

  return function(b) {

    return a * b;

  };

}
const double = multiply(2);

console.log(double(5)); // 10

```

`multiply`가 반환한 내부 함수는 `a` 값을 **클로저**로 기억하고, 이후에 `b`만 전달받아 계산합니다.

---

## # 4️⃣ 클로저 사용 시 주의할 점 – 메모리와 성능 관리

1. **불필요한 클로저 생성 방지**

   - 루프 안에서 함수를 매번 새로 만들면 메모리 사용량이 급증합니다. `for` 루프와 `let`을 활용하거나, 함수 외부에 재사용 가능한 함수를 정의하세요.

2. **전역 변수 오염 방지**

   - 클로저가 전역 객체에 접근하면 의도치 않은 사이드 이펙트가 발생할 수 있습니다. 가능한 한 **스코프를 제한**하고, 모듈 패턴을 활용해 전역 오염을 방지하세요.

3. **가비지 컬렉션(GC) 이해**

   - 클로저가 외부 변수를 계속 참조하면, 해당 변수가 가비지 컬렉션 대상이 되지 않아 메모리 누수가 발생할 수 있습니다. 필요 없어진 클로저는 **참조를 끊어** 메모리를 회수하도록 설계합니다.

---

## # 5️⃣ 실전 예제 – ‘Timothy의 도서관 페이지 기억하기’

Timothy가 도서관에서 책을 읽으며 **읽은 페이지 번호를 기억**하고 싶다고 가정해 봅시다. 페이지를 넘길 때마다 현재 페이지를 저장하고, 나중에 다시 열었을 때 마지막 페이지부터 이어서 읽을 수 있도록 하는 기능을 구현합니다.

```
javascript

function createReadingSession(bookTitle) {

  let lastPage = 0; // 현재 세션의 마지막 페이지 (프라이빗)

  return {

    goToPage: function(page) {

      if (page < 1) throw new Error('페이지 번호는 1보다 커야 합니다.');

      lastPage = page;

      console.log(`${bookTitle} - 현재 페이지: ${lastPage}`);

    },

    resume: function() {

      console.log(`${bookTitle} - 마지막으로 읽은 페이지: ${lastPage}`);

    }

  };

}

// 사용 예시

const timothySession = createReadingSession('JavaScript 비밀스러운 삶');

timothySession.goToPage(23);

timothySession.goToPage(45);

timothySession.resume(); // 'JavaScript 비밀스러운 삶 - 마지막으로 읽은 페이지: 45'

```

위 예제에서 `lastPage` 변수는 **클로저**를 통해 `createReadingSession` 외부에 노출되지 않으며, Timothy가 언제든지 마지막 페이지를 복원할 수 있게 합니다.

---

# # 결론 – 클로저를 마스터하고 코딩 실력을 한 단계 끌어올리세요

JavaScript **클로저**는 단순히 “함수가 기억한다”는 수준을 넘어, **데이터 은닉**, **모듈화**, **비동기 흐름 제어** 등 다양한 상황에서 핵심적인 역할을 합니다.

1. **클로저의 원리**(렉시컬 스코프와 환경 캡처)를 이해하면, 복잡한 비동기 로직도 깔끔하게 구현할 수 있습니다.

2. **실무 패턴**(모듈, 커링, 프라이버시)을 적용해 코드를 재사용 가능하고 유지보수하기 쉬운 구조로 바꿀 수 있습니다.

3. **주의점**(메모리 누수, 전역 오염)을 염두에 두고 설계한다면, 성능 저하 없이 안정적인 애플리케이션을 만들 수 있습니다.

> **행동 유도** – 지금 바로 위에 소개한 `createReadingSession` 예제를 직접 실행해 보세요. 그리고 자신의 프로젝트에 **클로저를 활용한 작은 모듈**을 하나 만들어 보는 것이 실력을 다지는 가장 빠른 방법입니다.

클로저를 제대로 이해하고 활용한다면, 당신도 **‘함수가 기억한다’는 마법**을 손쉽게 구현할 수 있습니다. 앞으로도 JavaScript의 숨겨진 비밀을 파헤치는 여정을 함께 하시길 바랍니다!

---

## # 참고 자료

- [The Secret Life of JavaScript: Understanding Closures (dev.to)](https://dev.to/aaron_rose_0787cc8b4775a0/the-secret-life-of-javascript-understanding-closures-40if)

- MDN Web Docs – [Closures](https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures)

- “You Don’t Know JS” – Kyle Simpson, *Scope & Closures*

---

*이 글은 **JavaScript 클로저**, **함수 기억**, **프로그래밍 기초**라는 SEO 키워드를 포함하여 초보자도 이해하기 쉬운 형태로 작성되었습니다. 검색 엔진 최적화를 위해 적절한 헤딩 구조와 키워드 배치를 적용했으며, 실제 코드 예시와 실전 활용 팁을 제공했습니다.*
