# JavaScript 클로저 완전 정복 – 함수가 기억하는 비밀을 파헤쳐 보자 (58자)

---

# # 서론 – “함수가 왜 기억을 할까?”

프로그래밍을 처음 시작한 사람들은 **함수**를 “입력값을 받아 결과를 반환하는 작은 기계”라고만 생각합니다. 그런데 JavaScript에서는 함수가 **자신이 선언될 때의 환경을 기억**하고, 그 기억을 바탕으로 동작하는 **클로저(Closure)** 라는 특별한 메커니즘이 존재합니다.

이 글에서는 *Chapter 4: Functions Remember* 라는 주제에 맞춰, **JavaScript 클로저**가 무엇인지, 왜 필요한지, 그리고 실제 예제로 어떻게 활용할 수 있는지를 초보자도 쉽게 이해할 수 있도록 단계별로 설명합니다.

> **SEO 키워드** : `JavaScript 클로저`, `함수 기억`, `스코프`

---

# # 1️⃣ 스코프와 클로저 – 기본 개념 잡기

| 용어 | 의미 |

|------|------|

| **스코프(Scope)** | 변수가 접근 가능한 영역. 전역·함수·블록 스코프 등 |

| **렉시컬 스코프(Lexical Scope)** | 함수는 **정의된 위치**의 스코프를 기억한다. |

| **클로저(Closure)** | 함수가 **외부 스코프**에 있는 변수들을 **함께 기억**하고, 나중에 실행될 때도 그 변수에 접근할 수 있는 현상 |

> **간단한 예시**

> 
```
js

> function makeCounter() {

>   let count = 0;               // 외부 스코프 변수

>   return function() {         // 내부 함수가 외부 변수에 접근

>     count += 1;

>     return count;

>   };

> }

> const counter = makeCounter(); // 클로저가 생성

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

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

> 
```

> `makeCounter`가 실행된 뒤에도 `count` 변수는 사라지지 않고, 반환된 함수가 **그 값을 기억**합니다. 이것이 바로 **함수가 기억하는** 메커니즘, 즉 **클로저**입니다.

---

# # 2️⃣ 클로저가 필요한 이유 – 데이터 은닉과 상태 유지

## # 2-1. 비공개 변수 만들기

클로저를 이용하면 **외부에서 직접 접근할 수 없는** 변수를 만들 수 있습니다. 이는 객체 지향 언어의 `private` 속성과 비슷한 효과를 줍니다.

```
js

function createSecret() {

  let secret = '🔒 비밀';

  return {

    reveal() { return secret; },

    change(newVal) { secret = newVal; }

  };

}
const box = createSecret();

console.log(box.reveal()); // 🔒 비밀

box.change('새 비밀');

console.log(box.reveal()); // 새 비밀

```

## # 2-2. 비동기 로직에서 상태 유지

버튼 클릭, 타이머, API 콜 등 **비동기** 상황에서도 클로저는 변수를 살아 있게 합니다.

```
js

function startTimer() {

  let seconds = 0;

  setInterval(() => {

    seconds++;

    console.log(`경과 시간: ${seconds}s`);

  }, 1000);

}
startTimer(); // 매초 증가하는 seconds를 클로저가 기억

```

---

# # 3️⃣ 클로저 사용 시 주의할 점 – 메모리 누수 방지

클로저가 **불필요하게 큰 객체**를 참조하면 가비지 컬렉터가 메모리를 회수하지 못해 **메모리 누수**가 발생할 수 있습니다.

| 방지 방법 | 설명 |

|----------|------|

| **필요 없는 레퍼런스 제거** | 사용이 끝난 변수는 `null` 혹은 `undefined` 로 초기화 |

| **스코프 최소화** | 클로저를 만들 때 가능한 한 작은 범위 안에서 선언 |

| **WeakMap 활용** | 객체를 키로 사용할 때 메모리 회수를 돕는다 |

```
js

function heavyTask() {

  const largeObj = { /* 수백 MB 데이터 */ };

  return function() {

    // 작업 수행 후 레퍼런스 해제

    console.log('작업 완료');

    // largeObj = null; // ← 이렇게 해주면 메모리 회수 가능

  };

}

```

---

# # 4️⃣ 실전 활용 사례 – 모듈 패턴 & 커링

## # 4‑1. 모듈 패턴 (Module Pattern)

클로저를 이용해 **비공개 데이터와 공개 API**를 한 파일에 깔끔하게 구성할 수 있습니다.

```
js

const TodoModule = (function() {

  let todos = []; // 비공개

  return {

    add(item) { todos.push(item); },

    list() { console.log(todos); }

  };

})();

TodoModule.add('JavaScript 공부');

TodoModule.list(); // ['JavaScript 공부']

```

## # 4‑2. 커링 (Currying)

함수 호출 시 일부 인자를 미리 채워 두고, 나중에 남은 인자를 받아 실행하는 기법도 클로저 덕분에 가능합니다.

```
js

function multiply(a) {

  return function(b) {

    return a * b;

  };

}
const double = multiply(2);

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

```

---

# # 5️⃣ 클로저 디버깅 팁 – 초보자를 위한 체크리스트

1. **변수 선언 위치 확인** – 클로저가 참조하는 변수가 어디서 선언됐는지 파악한다.

2. **콘솔 로그 활용** – 클로저 내부와 외부에서 변수 값을 출력해 흐름을 눈으로 확인한다.

3. **메모리 탭 확인** – 브라우저 개발자 도구 → Memory → Heap Snapshot을 통해 누수 여부를 검사한다.

4. **테스트 코드 작성** – Jest·Mocha 등으로 클로저가 기대한 대로 동작하는지 자동 검증한다.

```
js

test('counter increments correctly', () => {

  const counter = makeCounter();

  expect(counter()).toBe(1);

  expect(counter()).toBe(2);

});

```

---

# # 결론 – 오늘부터 클로저를 활용해 보세요!

- **클로저는** 함수가 **외부 스코프를 기억**하고, 이를 통해 **데이터 은닉**, **상태 유지**, **코드 재사용**을 가능하게 하는 강력한 도구입니다.

- **스코프와 렉시컬 환경**을 정확히 이해하고, **우선순위**와 **메모리 관리**를 염두에 두면 안전하게 사용할 수 있습니다.

> **실습 과제**

> 1. 위 예시 `makeCounter`를 직접 구현하고, 콘솔에 5번 호출해 보세요.

> 2. `TodoModule`을 변형해 **완료된 아이템만 필터링**하는 메서드를 추가해 보세요.

클로저를 제대로 활용하면 **코드가 더 깔끔해지고**, **버그 발생 가능성이 낮아집니다**. 오늘 배운 내용을 바탕으로 직접 코드를 짜보고, 질문이 있으면 댓글에 남겨 주세요. 함께 성장하는 개발 커뮤니티가 되길 바랍니다!

---

**SEO 키워드** : `JavaScript 클로저`, `함수 기억`, `스코프`

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