클로저
클로저
클로저(Closure)는 프로그래밍 언어에서 함수가 자신이 정의된 환경(스코프)의 변수를 기억하고 접근할 수 있도록 하는 중요한 소프트웨어 설계 개념이다. 특히 함수형 프로그래밍과 자바스크립트와 같은 동적 언어에서 핵심적인 역할을 하며, 캡슐화, 데이터 은닉, 콜백 함수 구현 등 다양한 설계 패턴에 활용된다.
클로저는 단순한 문법적 기능을 넘어서, 프로그램의 구조를 더 유연하고 강력하게 만들 수 있는 도구로 평가받는다. 본 문서에서는 클로저의 정의, 작동 원리, 활용 사례, 장단점 및 주의할 점에 대해 다룬다.
개요
클로저는 내부 함수(inner function)가 외부 함수의 변수를 참조하면서, 외부 함수가 실행을 종료한 후에도 그 변수에 접근할 수 있도록 하는 현상이다. 이는 렉시컬 스코핑(Lexical Scoping)이라는 개념과 밀접하게 관련되어 있다.
클로저는 주로 다음과 같은 상황에서 유용하다: - 상태를 유지해야 하는 함수 - 콜백이나 이벤트 핸들러에서 외부 데이터를 사용할 때 - 모듈 패턴을 통해 정보 은닉을 구현할 때
클로저의 작동 원리
1. 렉시컬 스코프 (Lexical Scoping)
클로저는 렉시컬 스코프 기반 언어에서만 가능하다. 렉시컬 스코프란, 함수가 어디에서 정의되었는지에 따라 변수의 접근 범위가 결정된다는 의미이다.
예를 들어, 자바스크립트에서 다음과 같은 코드를 살펴보자:
function outer() {
let outerVar = 'I am outside!';
function inner() {
console.log(outerVar); // outerVar를 참조
}
return inner;
}
const myFunc = outer();
myFunc(); // "I am outside!" 출력
여기서 inner
함수는 outer
함수 내에서 정의되었으므로, outerVar
에 접근할 수 있다. outer()
가 호출되고 종료된 후에도 myFunc
는 outerVar
를 기억하고 있다. 이 상태를 클로저라고 한다.
2. 실행 컨텍스트와 스코프 체인
함수가 호출되면 실행 컨텍스트가 생성되고, 이는 변수 객체, 스코프 체인, this
바인딩 등을 포함한다. 클로저는 내부 함수가 외부 함수의 변수 객체를 스코프 체인을 통해 계속 유지함으로써 작동한다.
즉, 내부 함수가 외부 함수의 변수를 참조할 때, 그 참조는 외부 함수의 실행이 끝나도 사라지지 않고, 메모리에 유지된다.
클로저의 활용 사례
1. 정보 은닉과 모듈 패턴
클로저는 공개되지 않은 변수를 유지하면서 특정 함수만 외부에 노출할 수 있게 해준다. 이를 모듈 패턴(Module Pattern)이라고 한다.
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
여기서 count
변수는 외부에서 직접 접근할 수 없으며, 오직 반환된 객체의 메서드를 통해서만 조작 가능하다. 이는 객체 지향 프로그래밍의 캡슐화 개념과 유사하다.
2. 콜백 함수와 이벤트 핸들러
이벤트 기반 프로그래밍에서 클로저는 외부 데이터를 콜백 함수 내에서 사용할 수 있게 해준다.
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 모두 3이 출력됨 (var의 호이스팅 문제)
}, 100);
}
위 코드는 예상과 달리 3, 3, 3
을 출력한다. 이는 [var](/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/JavaScript/var)
가 함수 스코프를 가지기 때문이다. 이를 클로저를 이용해 해결할 수 있다:
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 0, 1, 2 (let은 블록 스코프)
}, 100);
}
또는 즉시 실행 함수(IIFE)를 사용하여 클로저를 명시적으로 만들 수 있다:
for (var i = 0; i < 3; i++) {
(function(index) {
setTimeout(function() {
console.log(index);
}, 100);
})(i);
}
장점과 단점
항목 | 설명 |
---|---|
장점 | - 상태 유지 가능 - 정보 은닉 가능 - 함수형 프로그래밍 패턴 지원 |
단점 | - 메모리 누수 가능성 (변수를 계속 참조) - 디버깅이 어려울 수 있음 - 과도한 사용 시 성능 저하 |
특히 메모리 누수는 클로저를 사용할 때 주의해야 할 점이다. 외부 함수의 변수가 내부 함수에 의해 참조되고 있으면, 가비지 컬렉터가 이를 회수하지 못할 수 있다.
참고 자료 및 관련 문서
- MDN Web Docs - Closures
- "JavaScript: The Good Parts" - Douglas Crockford
- 함수형 프로그래밍 패턴
- 스코프와 호이스팅
- 가비지 컬렉션 (Garbage Collection)
클로저는 고급 프로그래밍 기법을 이해하는 데 필수적인 개념이며, 현대 웹 개발에서 널리 사용된다. 이를 올바르게 이해하고 활용하면 더 견고하고 유지보수하기 쉬운 코드를 작성할 수 있다.
이 문서는 AI 모델(qwen-3-235b-a22b-instruct-2507)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.