
클로저 : 함수와 함수가 선언된 렉시컬 환경을 함께 기억하여, 외부 함수의 생명 주기가 끝난 후에도 중첩 함수가 그 환경의 변수들을 참조할 수 있게 합니다.
이 클로저 기능을 가능하게 하는것은 렉시컬 스코프 덕분 입니다. 렉시컬 스코프란 코드가 작성된 위치에 스코프가 결정 되는 방식을 말합니다. 따라서 어디에서 호출되었는지가 아니라 어디에서 선언되었는지에 따라 그 함수가 접근 할 수 있는 변수가 결정이 됩니다.
그런데 저러한 클로저가 많으면 불필요한 메모리 점유에 대해서 걱정 할 수 있습니다.
하지만 자바스크립트 엔진에서 최적화가 잘 되어 있기 때문에 클로저가 참조하고 있지 않은 식별자는 기억하지 않습니다. 즉 기억 해야만 하는 식별자를 기억하기 때문에 메모리 낭비라고 볼 수 없습니다. 다만, 필요치 않은 클로저는 적극적으로 해제해야 합니다.
그래서 이런 클로저 기능을 가지고 뭘 할 수 있는건데요???
그 외 활용및 응용하여 다양하게 사용할 수 있습니다.
function createCounter() {
// count 변수를 은닉하자!
let count = 0;
return {
increment : function () {
count++;
return count;
},
decrement : function () {
count++;
return count;
},
current : function () {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.increment()); // 3
console.log(counter.decrement()); // 4
console.log(counter.current()); // 4
가장 대표적인 예시로 setTimeOut 함수로, 해당 비동기 함수안에 콜백함수를 삽입하여 해당 작업이 시작된 시점의 변수 값을 안전하게 참조 할 수 있게 합니다.
// createDelayedLogger 함수는 두개의 인수(message,delay)를 받아 클로저를 반환
// 반환된 함수가 호출될때 비동기적으로 message 출력
function createDelayedLogger(message, delay) {
return function() {
setTimeout(function() {
console.log(message);
}, delay);
};
}
const logHello = createDelayedLogger("Hello, World!", 1000);
const logGoodbye = createDelayedLogger("Goodbye, World!", 2000);
logHello(); // 1초 후에 "Hello, World!" 출력
logGoodbye(); // 2초 후에 "Goodbye, World!" 출력