JavaScript에서 **클로저(Closure)**는 함수와 그 함수가 선언된 어휘적 환경(Lexical Environment)의 조합을 말합니다. 즉, 함수가 외부 스코프의 변수에 접근할 수 있는 기능을 의미합니다.
📌 기본 개념
클로저는 다음과 같은 조건에서 생성됩니다:
- 함수 안에 함수가 정의되어 있고,
- 내부 함수가 외부 함수의 변수에 접근할 수 있으며,
- 외부 함수의 실행이 끝난 뒤에도 내부 함수가 여전히 그 변수에 접근할 수 있을 때 클로저가 됩니다.
function outer() {
let count = 0;
return function inner() {
count++;
console.log(count);
}
}
const counter = outer();
counter(); // 1
counter(); // 2
위 예제에서 inner() 함수는 outer()의 지역 변수 count에 접근합니다. outer()의 실행이 끝났음에도 counter()가 count에 계속 접근할 수 있는 이유는 클로저 때문입니다.
📦 클로저의 활용 예시
1. 데이터 은닉과 캡슐화
function createCounter() {
let value = 0;
return {
increment: () => ++value,
decrement: () => --value,
getValue: () => value
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getValue()); // 2
→ 외부에서는 value를 직접 접근할 수 없고, increment/decrement 같은 함수만 통해 제어할 수 있습니다.
2. 콜백이나 비동기 처리에서의 변수 보존
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 항상 3 출력
}, 1000);
}
→ var는 함수 스코프라서 클로저가 i의 동일한 참조를 유지하기 때문에 3이 반복됨.
해결하려면:
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 0, 1, 2 출력
}, 1000);
}
→ let은 블록 스코프라 클로저가 각각의 i를 따로 캡처함.
🧠 클로저가 유용한 이유
- 상태를 은닉하면서 유지할 수 있음
- 함수형 프로그래밍에서 고차 함수 구현에 필수
- 이벤트 핸들러나 비동기 로직에서 변수 유지
- 모듈화와 캡슐화 구현에 핵심 도구
⚠️ 주의할 점
- 메모리 누수: 클로저는 외부 변수를 참조하므로, 예상보다 오래 메모리에 남아 있을 수 있음
- 과도한 남용은 코드 복잡도를 높임