2025. 3. 25. 23:01ㆍ개발자 블로깅/오늘의 TIL
📝개요
분명 들어봤던 단어! 너는 왜 항상 내 기억에서 사라지는거니.. 기술 면접의 시작으로 절대 잊을 수 없는 단어가 되어버린 "클로저", 다시 이해해보기
클로저는 초반에는 쉽지 않아도, 한 번 정확하게 이해하면 각종 상황에서 상태 저장, 정보 은닉, 비동기 처리 등에 유용하게 쓰이면 강력한 무기입니다.
📚 목차
1. 클로저란?
2. 클로저가 왜 필요할까?
3. 클로저 언제 사용하나요?
4. 실전 예제
5. 클로저와 관련된 주의점
6. 정보 정리 & 마무리
7. (부모) 클로저 한눈에 보기 : Venn Diagram
✅ 1. 클로저란? closure 폐쇄
클로저는 함수와 그 함수가 선언되었을 때의 렉시컬 환경과의 조합이다.
렉시컬 환경이란?
실행 중인 코드가 사용하는 변수, 상수, 함수 정보를 저장한는 내부 구조 (메모리 구조)
- 자바스크립트 엔진 내부에서 만들어지는 객체(구조)
- 함수가 생성되거나 실행될 때 자동으로 생성
렉시컬 스코프란?
(함수가 실행되는 위치가 아니라) 함수가 어디에 정의되었는지에 따라 상위 스코프가 결정되는 규칙
자바스크립트에서 쉽게 말하면? 함수가 생성될 때의 외부 변수 환경(스코프)을 기억하는 함수 를 말합니다.
더 쉽게 설명하면? 내부 함수가 외부 함수의 변수에 접근할 수 있는 상태!
즉, 함수가 끝났다고 외부 변수들이 사라지지 않고, 내부 함수가 계속 기억하고 접근할 수 있다는 것 입니다.
클로저 예제 코드
function outer() {
let secret = "🔐 비밀";
function inner() {
console.log(secret); // 외부 변수에 접근!
}
return inner;
}
const myFunc = outer(); // outer 실행 → inner 함수 리턴
myFunc(); // 🔐 비밀 (클로저로 외부 변수 접근)
- outer() 실행 → secret은 outer의 지역 변수
- inner()는 secret에 접근 가능
- outer()는 종료됐지만, inner()가 여전히 secret을 기억하고 있음 → 이게 클로저
✅ 2. 클로저가 왜 중요한가?
1. 상태 유지 (데이터 숨기기)
function counter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const clickCounter = counter();
clickCounter(); // 1
clickCounter(); // 2
clickCounter(); // 3
- count는 외부에서 접근 불가
- clickCounter만 내부에서 조작 가능 → 은닉 + 상태 유지
2. 비동기 처리와 반복문에서 유용
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 출력: 3 3 3
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 출력: 0 1 2 (클로저로 각각의 i 기억)
✅ 3. 클로저 언제 사용하나요?
- 상태 저장 (counter 만들기)
- private 변수 숨기기
- 비동기/반복문 변수 유지
✅ 4. 실전 예제
1. 카운터 만들기 (상태 보존 + 은닉화)
function createCounter() {
let count = 0;
return {
increment() {
count++;
console.log(count);
},
decrement() {
count--;
console.log(count);
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
console.log(counter.getCount()); // 1
특징
- count는 외부에서 직접 접근 불가 (private)
- 함수들이 count에 접근하는 클로저 구조
- 상태 저장 + 은닉화 + 캡슐화 구현
2. 함수 팩토리 (값을 기억하는 함수 생성기)
function makeMultiplier(multiplier) {
return function (value) {
return value * multiplier;
};
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
특징
- multiplier는 외부 함수의 매개변수지만,
- 내부 함수가 그 값을 계속 기억함 → 클로저
- 다양한 설정값을 함수로 캡슐화해서 재사용 가능
이런 구조 덕분에 상태를 은닉하거나, 콜백 함수에서도 안전하게 값을 유지하는 로직을 만들 수 있어요.
✅ 5. 클로저와 관련된 주의점
클로저는 매우 강력한 기능이지만, 잘못 사용하면 오히려 메모리 누수, 예상치 못한 동작, 디버깅 어려움 등의 문제를 유발할 수 있습니다. 다음은 클로저 사용 시 주의해야 할 대표적인 사항들입니다.
🔸 1. 불필요한 클로저로 인한 메모리 누수
클로저는 외부 변수를 참조하기 때문에 해당 변수가 GC(Garbage Collection) 대상이 되지 않아 메모리에 오래 남아 있을 수 있습니다.
function createBigClosure() {
const bigData = new Array(1000000).fill('📦');
return function () {
console.log(bigData[0]);
};
}
→ 위 코드에서 클로저가 bigData에 접근하고 있어, 해당 클로저가 참조되는 한 bigData도 메모리에 유지됩니다.
🔸 2. 반복문 안에서의 클로저 사용 주의
var를 사용할 경우 모든 클로저가 하나의 동일한 변수를 참조하게 되어 예상치 못한 결과가 발생할 수 있어요.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // 출력: 3, 3, 3
해결 방법은 let을 사용하거나, IIFE(즉시실행함수)를 이용해 스코프를 분리하는 것입니다.
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
} // 출력: 0, 1, 2
🔸 3. 디버깅이 어려울 수 있음
클로저는 숨겨진 상태를 내부적으로 유지하기 때문에, 디버깅 시에 어떤 값이 유지되고 있는지 추적이 어려울 수 있습니다. → 따라서 가독성이 중요한 코드에서는 불필요한 클로저 남용을 피하고 명확하게 함수 범위를 설계하는 것이 중요합니다.
✅ 6. 정보 정리 & 마무리
클로저는 JavaScript의 핵심 개념 중 하나로, 함수가 자신이 선언된 렉시컬 환경(Lexical Environment)을 기억하여 외부 스코프의 변수에 접근할 수 있는 구조를 말합니다
클로저의 핵심 포인트
- 함수가 만들어질 때의 스코프를 기억함
- 외부 함수가 종료되어도 변수에 접근 가능
- 상태 저장, 은닉화, 비동기 로직 등에 유용
주의해야 할 점
- 메모리 누수 주의
- 반복문 내 사용 시 let 또는 IIFE 스코프 분리
- 디버깅 어려움 -> 가독성 고려
=> 클로저를 이해하면 실무에서 다양한 기능을 효율적이고 안전하게 구현할 수 있음
✅ 7. 클로저 한눈에 보기 : Venn Diagram

마무리
클로저는 반환된 내부 함수가 자신이 선언됐을 때의 환경(Lexical environment 렉시컬 환경)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말합니다.
클로저는 단순한 이론이 아니라, 실무에서도 굉장히 자주 쓰이는 패턴입니다.
상태 저장, 은닉화, 함수 팩토리 구성 등 다양한 방식으로 활용되니, 꼭 자신의 코드에 적용해보세요!
참고
Chat GPT
https://poiemaweb.com/js-closure
'개발자 블로깅 > 오늘의 TIL' 카테고리의 다른 글
JavaScript 는 싱글 스레드 언어인데 비동기 작업이 가능한가? (0) | 2025.04.01 |
---|---|
[ JavaScript ] 비동기 처리를 위한 Promise 객체 (0) | 2025.03.28 |
[ JavaScript ] Var, Let, Const 변수의 호이스팅과 TDZ(Temporal Dead Zone) (0) | 2025.03.25 |
디자인 패턴의 역사 (1) | 2025.02.19 |