
함수가 자신이 선언된 환경(스코프)을 기억하고, 그 환경 밖에서도 그 변수들에 접근할 수 있게 해주는 기능
클로저(Closure)는 자바스크립트에서 매우 중요한 개념으로,
함수가 선언될 당시의 스코프(Lexical Scope)를 기억하여,
함수가 생성된 이후에도 그 스코프의 변수에 접근할 수 있게 하는 기능입니다.
다르게 표현하면,
✅ 함수가 자신이 태어난 환경을 기억하는 것
✅ 외부 함수의 실행이 끝나더라도, 내부 함수가 외부 변수에 접근 가능한 것
이라고 할 수 있습니다.
이러한 클로저는 자바스크립트의 함수가 일급 객체(First-Class Object) 라는 특성과 렉시컬 스코프(Lexical Scope) 구조에서 만들어집니다.
function outerFunction(outerVariable) {
return function innerFunction(innerVariable) {
console.log(`🌏 Outer Variable: ${outerVariable}`);
console.log(`🌟 Inner Variable: ${innerVariable}`);
};
}
const newFunction = outerFunction('outside');
newFunction('inside');
outerFunction('outside') 를 호출하면
→ outerVariable은 'outside'로 설정되고,
→ innerFunction을 반환합니다.
newFunction('inside') 를 실행하면
→ 내부에서 outerVariable과 innerVariable을 모두 참조합니다.
중요한 점은,
→ outerFunction은 이미 실행이 끝났는데도, innerFunction은 outerVariable에 접근 가능하다는 것!
→ 이게 바로 클로저입니다.
클로저는 다음과 같은 상황에서 매우 유용하게 사용됩니다.
클로저를 활용하면 외부에서는 접근할 수 없는 비공개 변수를 만들 수 있습니다.
function createCounter() {
let count = 0; // 외부에서는 접근 불가
return {
increment: () => {
count++;
console.log(`📈 Count: ${count}`);
},
decrement: () => {
count--;
console.log(`📉 Count: ${count}`);
},
getCount: () => {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 📈 Count: 1
counter.increment(); // 📈 Count: 2
counter.decrement(); // 📉 Count: 1
console.log(counter.getCount()); // 1
// 외부에서 count에 직접 접근 불가능
// console.log(counter.count); → undefined
✅ 데이터 보호, 상태 유지에 효과적
✅ 외부에서는 count 변수에 직접 접근 불가, 함수 통해서만 접근 가능
비동기 작업에서 특정 변수의 상태를 나중에 참조해야 할 때 클로저가 유용합니다.
function createLogger(name) {
return function() {
console.log(`📝 Logger: ${name}`);
};
}
const logger = createLogger('MyApp');
setTimeout(logger, 1000); // 1초 후에 📝 Logger: MyApp 출력
✅ 1초가 지나도 name 변수를 기억하고 있습니다.
✅ 클로저가 스코프를 "기억"하기 때문
자주 발생하는 실수 & 클로저의 위력
function createFunctions() {
const functions = [];
for (let i = 0; i < 3; i++) {
functions.push(function() {
console.log(`🔢 Index: ${i}`);
});
}
return functions;
}
const funcs = createFunctions();
funcs[0](); // 🔢 Index: 0
funcs[1](); // 🔢 Index: 1
funcs[2](); // 🔢 Index: 2
✅ let을 사용해 블록 스코프를 유지하면,
각 함수가 생성될 때의 i 값을 클로저로 기억해둡니다.
var로 선언하면, 모든 출력값이 3이 되는 이유도 클로저 + var의 함수 스코프 특성 때문입니다.
클로저는 모듈화에도 자주 사용됩니다.
const CounterModule = (function() {
let count = 0;
function increment() {
count++;
console.log(`🚀 Count: ${count}`);
}
function getCount() {
return count;
}
return {
increment,
getCount
};
})();
CounterModule.increment(); // 🚀 Count: 1
CounterModule.increment(); // 🚀 Count: 2
console.log(CounterModule.getCount()); // 2
✅ 필요한 기능만 외부에 노출
✅ 내부 데이터(count)는 은닉
클로저는 부분 적용 함수(Partial Application) 를 구현할 때도 자주 사용됩니다.
function multiply(x) {
return function (y) {
return x * y;
};
}
const double = multiply(2);
const triple = multiply(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
✅ double은 x = 2인 환경을 기억하는 클로저
✅ triple은 x = 3인 환경을 기억
→ 각각 다른 상태를 기억하는 함수가 만들어집니다.
클로저는 처음엔 조금 헷갈릴 수 있지만,
핵심은 다음 한 문장으로 요약됩니다.
"함수가 선언될 당시의 스코프를 기억하여, 생성된 이후에도 그 스코프에 접근할 수 있는 기능"
주로 데이터 보호, 상태 유지, 모듈화에 많이 사용되며, 자바스크립트의 유연하고 강력한 기능 중 하나입니다.