JavaScript Function Closures
JavaScript Closures: 클로저 개념과 사용법
- *클로저(Closure)**는 JavaScript 함수가 외부 함수의 변수에 접근할 수 있는 강력한 기능입니다. 클로저는 내부 함수가 외부 함수의 실행 컨텍스트가 종료된 후에도 외부 함수의 변수를 기억하고 참조할 수 있게 해줍니다. 이로 인해 데이터 은닉이나 상태 유지 같은 중요한 프로그래밍 기법을 구현할 수 있습니다.
이 가이드는 JavaScript 클로저의 개념과 사용법을 설명하고, 실용적인 예시를 제공합니다.
1. 클로저의 기본 개념
- *클로저(Closure)**는 함수가 선언된 스코프에서 변수에 접근할 수 있는 함수를 말합니다. 즉, 내부 함수가 외부 함수의 변수를 기억하고 참조할 수 있을 때, 해당 내부 함수는 클로저라고 합니다.
1.1. 클로저의 기본 구조
function outer() {
const outerVar = 'I am from outer';
function inner() {
console.log(outerVar); // 외부 함수의 변수에 접근
}
return inner;
}
const innerFunction = outer(); // outer() 호출 시 inner 함수 반환
innerFunction(); // 'I am from outer' 출력
1.2. 클로저의 특징
- 내부 함수는 외부 함수의 변수에 접근할 수 있습니다.
- 외부 함수가 종료된 후에도 내부 함수는 외부 함수의 변수를 기억하고 참조할 수 있습니다.
- 함수가 선언된 위치에 따라 변수 스코프가 결정되며, **
this
*와는 무관합니다.
2. 클로저 동작 방식
클로저는 외부 함수가 종료된 후에도 외부 함수의 변수 환경을 저장하고 유지합니다. 이는 내부 함수가 외부 함수의 변수를 참조할 수 있게 해줍니다.
2.1. 클로저가 변수에 접근하는 방식
function counter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const increment = counter(); // counter() 호출로 내부 함수 반환
increment(); // 1
increment(); // 2
increment(); // 3
counter()
함수는count
변수를 생성하고, 내부 함수를 반환합니다.- 반환된 함수는
count
변수를 참조하며, 함수가 호출될 때마다count
값이 증가합니다. - 외부 함수(
counter
)가 종료된 후에도, 내부 함수는count
변수를 계속 기억하고 있습니다.
3. 클로저의 실용적인 사용 예시
3.1. 데이터 은닉과 캡슐화
클로저는 변수를 은닉하고, 외부에서 직접 접근할 수 없도록 보호할 수 있습니다. 이를 통해 데이터를 안전하게 관리하는 캡슐화 기법을 구현할 수 있습니다.
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
console.log(count);
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getCount()); // 2
count
변수는createCounter()
함수 내부에서만 존재하며, 외부에서 직접 접근할 수 없습니다.- *
increment()
*와getCount()
메서드를 통해서만 **count
*에 접근할 수 있습니다. - 이를 통해 데이터의 무분별한 변경을 막을 수 있습니다.
3.2. 함수 공장(Function Factory)
클로저를 사용하면 함수를 반환하는 함수, 즉 함수 공장을 만들 수 있습니다. 이를 통해 동일한 함수 논리에 다양한 값을 적용하여 유사한 동작을 하는 함수들을 쉽게 생성할 수 있습니다.
function createMultiplier(multiplier) {
return function(value) {
return value * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
- *
createMultiplier()
*는 곱셈 함수를 반환하는 함수 공장입니다. multiplier
값에 따라 다른 함수를 생성하여, 다양한 동작을 수행할 수 있습니다.
4. 클로저의 메모리 관리
클로저는 외부 함수의 변수를 계속 유지하기 때문에, 메모리 관리에 주의해야 합니다. 클로저가 너무 많거나, 오랫동안 사용되지 않는 클로저가 존재할 경우 메모리 누수가 발생할 수 있습니다.
4.1. 클로저와 메모리 누수 방지
클로저를 사용한 후에는, 필요하지 않은 참조를 제거하여 메모리 누수를 방지하는 것이 좋습니다.
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
console.log(count);
},
reset: function() {
count = 0; // 외부 변수 초기화
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.reset(); // count 값을 0으로 리셋
counter.increment(); // 1
reset()
메서드를 추가하여 외부 변수를 필요할 때 초기화할 수 있습니다.- 이를 통해 메모리 누수를 방지하고, 클로저 내부 변수를 적절히 관리할 수 있습니다.
5. 즉시 실행 함수와 클로저 (IIFE와 클로저)
- *즉시 실행 함수(IIFE: Immediately Invoked Function Expression)**는 즉시 호출되며, 클로저를 활용하여 변수를 은닉하거나 초기화하는 데 사용될 수 있습니다.
5.1. IIFE와 클로저 사용 예시
const counter = (function() {
let count = 0;
return function() {
count++;
console.log(count);
};
})();
counter(); // 1
counter(); // 2
- 즉시 실행 함수는 한 번 호출되며, 내부 변수를 은닉하고, 클로저를 통해 외부에서 계속 참조할 수 있습니다.
- 변수 스코프를 지역적으로 제한하고, 전역 오염을 방지합니다.
6. 클로저의 this
바인딩
클로저 내에서 **this
**는 외부 함수의 **this
**를 그대로 유지하지 않습니다. 클로저 내에서
**this
**가 다른 컨텍스트를 가리킬 수 있으므로, 이를 주의해서 사용해야 합니다.
6.1. 클로저와 this
예시
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, my name is ${this.name}`);
const innerFunction = function() {
console.log(`Inner function: ${this.name}`); // `this`는 전역 객체를 가리킴
};
innerFunction();
}
};
person.greet();
// Hello, my name is Alice
// Inner function: undefined (브라우저에서는 전역 객체의 this를 가리키므로 undefined)
6.2. 클로저 내에서 this
해결 방법
해결 방법 1: 변수에 this
저장
const person = {
name: 'Alice',
greet: function() {
const self = this; // `this`를 변수로 저장
console.log(`Hello, my name is ${self.name}`);
const innerFunction = function() {
console.log(`Inner function: ${self.name}`);
};
innerFunction();
}
};
person.greet();
// Hello, my name is Alice
// Inner function: Alice
해결 방법 2: 화살표 함수 사용
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, my name is ${this.name}`);
const innerFunction = () => {
console.log(`Inner function: ${this.name}`); // 화살표 함수는 상위 스코프의 this를 상속
};
innerFunction();
}
};
person.greet();
// Hello, my
name is Alice
// Inner function: Alice
요약
JavaScript 클로저는 함수가 외부 함수의 변수에 영구적으로 접근할 수 있는 능력을 제공하여 데이터 은닉과 상태 유지 같은 중요한 기능을 구현할 수 있습니다.
- 클로저는 외부 함수의 변수를 기억하고, 내부 함수에서 참조할 수 있습니다.
- 이를 통해 데이터 은닉, 상태 유지, 함수 공장과 같은 다양한 프로그래밍 패턴을 구현할 수 있습니다.
- 메모리 관리에 주의해야 하며, 필요할 때는 변수 초기화 등을 통해 메모리 누수를 방지해야 합니다.
this
바인딩에 주의하여, 화살표 함수나this
저장 같은 방법으로 클로저 내에서 올바르게 사용할 수 있습니다.
클로저는 JavaScript의 유연성과 강력함을 보여주는 중요한 개념으로, 상태를 유지하면서도 은닉할 수 있는 함수를 만들 때 유용하게 사용됩니다.