본 내용은 클로저에 대하여 계속해서 내용을 추가할 예정이며, 기입일을 기준으로 계속해서 내용 업데이트할 계획입니다.
Node.js 클로저(Closure)
•
클로저는 함수가 생성될 때의 렉시컬 스코프(lexical scope) 를 기억하고, 함수가 실행되는 동안에도 해당 스코프에 접근할 수 있는 기능
•
자바스크립트의 함수가 일급 객체(First-Class Object)이기 때문에 가능
•
비동기 프로그래밍, 데이터 은닉, 콜백 관리, 커링(currying) 등 다양한 패턴에서 사용됨
•
클로저는 자바스크립트 고유의 개념이 아니라 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어(Functional Programming language: 얼랭(Erlnag), 스칼라(Scala), 하스켈(Haskell), 리스프(Lisp)…)에서 사용되는 중요한 특성이다.
1. 클로저의 기본 개념
1-1. 렉시컬 스코프와 클로저
•
자바스크립트는 렉시컬 스코프(Lexical Scope)를 사용하여 변수를 찾음
•
함수가 선언될 당시의 스코프를 기억하며, 실행할 때에도 그 스코프에 접근 가능
예제 1: 기본적인 클로저 개념
function outer() {
let count = 0; // 외부 함수의 변수
function inner() { // 내부 함수
count++; // 외부 변수 접근 가능
console.log(count);
}
return inner; // 내부 함수 반환
}
const closureFunc = outer(); // outer 실행 -> inner 반환
closureFunc(); // 1
closureFunc(); // 2
closureFunc(); // 3
JavaScript
복사
설명
•
outer()가 실행되면 inner() 함수를 반환
•
closureFunc 변수는 inner()를 가리킴
•
inner()는 outer()의 count 변수에 접근 가능하며, 값이 유지됨
2. Node.js에서의 클로저 활용
2-1. 비동기 콜백에서 클로저
Node.js에서 클로저는 비동기 프로그래밍에서 자주 사용됨
예제 2: 비동기 콜백에서의 클로저
function delayedMessage(message, delay) {
setTimeout(function() {
console.log(message);
}, delay);
}
delayedMessage("Hello, Node.js!", 1000); // 1초 후 출력
JavaScript
복사
설명
•
setTimeout의 콜백 함수는 message 값을 기억하여 일정 시간 후에도 접근 가능
2-2. 데이터 은닉 및 모듈화
•
클로저를 사용하면 특정 변수에 대한 직접 접근을 차단하여 데이터 은닉(encapsulation) 가능
예제 3: 데이터 은닉
function counter() {
let count = 0; // 외부에서 접근 불가능한 변수
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
}
};
}
const myCounter = counter();
myCounter.increment(); // 1
myCounter.increment(); // 2
myCounter.decrement(); // 1
console.log(myCounter.count); // undefined (직접 접근 불가)
JavaScript
복사
설명
•
count 변수는 counter() 함수 내부에 존재하며, 직접 접근할 수 없음
•
increment()와 decrement()만 count를 조작할 수 있음
2-3. 클로저를 이용한 커링(currying)
•
클로저를 활용하면 커링(Currying) 기법을 사용할 수 있음
예제 4: 클로저를 이용한 커링
function multiply(x) {
return function(y) {
return x * y;
};
}
const double = multiply(2);
console.log(double(5)); // 10
console.log(double(10)); // 20
const triple = multiply(3);
console.log(triple(5)); // 15
JavaScript
복사
설명
•
multiply(x) 함수는 x를 기억하는 클로저를 생성
•
double은 multiply(2) 실행 결과로 생성된 클로저를 저장하여 y 값을 입력받아 x * y 연산 수행
2-4. 클로저를 활용한 API 요청 제한
•
클로저를 활용하면 특정 요청의 빈도를 제한하는 레이트 리미터(rate limiter) 기능 구현 가능
예제 5: 요청 제한
function createRateLimiter(limit, interval) {
let count = 0;
let startTime = Date.now();
return function() {
let currentTime = Date.now();
if (currentTime - startTime > interval) {
count = 0;
startTime = currentTime;
}
if (count < limit) {
count++;
console.log("Request allowed");
} else {
console.log("Rate limit exceeded");
}
};
}
const request = createRateLimiter(3, 5000);
request(); // Request allowed
request(); // Request allowed
request(); // Request allowed
request(); // Rate limit exceeded
JavaScript
복사
설명
•
createRateLimiter(3, 5000)는 5초 동안 최대 3번만 요청 허용
•
request()가 호출될 때마다 현재 시간과 비교하여 제한 여부 결정
3. 주의할 점
3-1. 메모리 누수 가능성
•
클로저는 내부에서 참조하는 변수를 유지하므로, 불필요한 클로저 유지 시 메모리 누수 발생 가능
•
해결 방법: 더 이상 필요하지 않은 경우 클로저의 참조를 제거하거나, null로 설정
예제 6: 메모리 누수 방지
function createClosure() {
let largeData = new Array(1000000).fill("data");
return function() {
console.log(largeData.length);
};
}
const closureFunc = createClosure();
closureFunc(); // 1000000
// 메모리 해제
closureFunc = null;
JavaScript
복사
설명
•
closureFunc가 null로 설정되면, largeData 배열도 해제됨
4. 정리
•
클로저는 함수가 생성될 당시의 스코프를 기억하고 유지하는 개념
•
비동기 콜백, 데이터 은닉, 커링, API 요청 제한 등 다양한 활용 가능
•
메모리 누수 방지 필요
참고자료
안녕하세요
•
관련 기술 문의와 R&D 공동 연구 사업 관련 문의는 “glory@keti.re.kr”로 연락 부탁드립니다.
Hello 
•
For technical and business inquiries, please contact me at “glory@keti.re.kr”