클로저(Closure)는 JavaScript의 중요한 개념 중 하나로, 함수와 그 함수가 선언될 때의 환경(lexical scope)을 함께 기억하는 함수이다. 클로저를 이해하기 위해서는 먼저 스코프(scope)와 함수의 작동 방식에 대한 이해가 필요하다.
클로저는 주로 다음과 같은 특징을 가진다.
JavaScript는 함수가 생성될 때의 스코프를 기억한다. 이때 변수가 어떻게 접근되는지를 이해하는 것이 클로저를 이해하는 데 중요하다.
function outerFunction() {
const outerVariable = 'I am from outer function';
function innerFunction() {
console.log(outerVariable); // 'I am from outer function'
}
return innerFunction;
}
const myInnerFunction = outerFunction();
myInnerFunction(); // 'I am from outer function'
위의 예제에서 outerFunction 내부에서 정의된 innerFunction은 outervariable에 접근할 수 있다. outerFunction이 실행되고 종료되더라도 innerFunction은 여전히 outerVariable에 접근할 수 있다. 이것이 클로저의 기본 작동 방식이다.
function createCounter() {
let count = 0; // private variable
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getCount()); // 2
counter.decrement(); // 1
console.log(counter.getCount()); // 1
위의 예제에서는 createCounter 함수가 클로저를 사용하여 count 변수를 은닉한다. 외부에서는 count 변수에 직접 접근할 수 없지만, increment, decrement, getCount 메서드를 통해서만 접근할 수 있다.
function makeCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter1 = makeCounter();
const counter2 = makeCounter();
counter1(); // 1
counter1(); // 2
counter2(); // 1
counter2(); // 2
위의 예제에서 makeCounter 함수는 각각 독립적인 count 변수를 가진 두 개의 카운터를 생성한다. counter1과 counter2는 서로의 count 변수에 영향을 미치지 않는다.
클로저는 강력한 기능을 제공하지만, 잘못 사용할 경우 메모리 누수(memory leak) 문제를 일으킬수 있다. 클로저가 참조하는 변수가 더 이상 필요하지 않더라도 메모리에서 해제되지 않기 때문이다. 따라서 클로저를 사용할 때는 메모리 관리에 유의해야 한다.