내부 함수가 외부 함수의 변수 환경(스코프)을 기억하고, 외부 함수가 종료된 후에도 해당 변수를 사용할 수 있도록 한 기능이다.
closure라는 단어에서 처럼 폐쇄 환경에 대한 개념이다.
기본적으로 함수는 외부의 변수를 받아서 실행되지만 함수 내부에 또다른 함수를 정의하는 경우가 있다.
이런 함수를 중첩 함수(nested function)라고 하는데 구조는 대강 다음과 같다.
function outerFunction(x) {
function innerFunction(y) {
}
}
클릭하여 코드 복사
이렇게 내부 함수 입장에선 외부 함수의 스코프{}로 인해서 폐쇄된 환경이 되기 때문에 클로저라 부른다.
뭐 그렇다고 저런 모양 자체를 클로저라고 하는 것은 아니고 클로저란 저런 폐쇄 환경에서 내부 함수에 사용되는 기능에 대한 정의이다.
- 정의:
- 클로저는 함수와 그 함수가 선언된 어휘적 환경(렉시컬 환경)의 조합이다.
- 쉽게 말해, 내부 함수가 외부 함수의 변수에 접근할 수 있는 현상이다.
- 핵심 원리:
- 내부 함수는 외부 함수의 스코프(변수 환경)를 기억한다.
- 외부 함수가 종료된 후에도 내부 함수는 이 스코프에 접근하여 변수를 사용할 수 있다.
개념 자체가 복잡하기 때문에 예시와 함께 확인하는 것이 이해가 쉽다.
function CM(x) {
function MY(y) {
return x * y;
}
return MY;
}
const double = CM(2);
const triple = CM(3);
console.log(double(5)); // 출력: 10
console.log(triple(5)); // 출력: 15
클릭하여 코드 복사
- 예를 들어서 CM이라는 함수(외부 함수)가 있다. 그 함수 안에는 MY라는 내부 함수가 있다.
- 여기서 x에 각각 2와 3을 넣은 상태를 변수로 선언 했다.
- const double = CM(2); const triple = CM(3);
- return MY로 MY 함수의 값을 반환하기 때문에
- double과 triple은 각각 x에 2와 3을 넣은 MY 함수의 값
- 즉 2y, 3y로 기억돼있을 것이다.
그렇다면 여기에서 double() = x에 2를 넣은 MY함수의 값 = 2 * y에 5를 인수로 넣는다면 매개 변수 y에 5가 할당되어 2*5 = 10이라는 결과가 나올 것이다.
여기서 중요한 것은 함수 CM은 이미 한번 호출되어 종료가 된 시점임에도 불구하고(const double = CM(2);) 매개변수 x에 인수가 넣어진 상태가 유지되어(기억되어) 내부 변수의 매개 변수에 인수를 넣었을 때, 계산이 깔끔하게 이루어졌다는 점이다.
만약에 const double = CM(2);이어도 이미 호출이 끝났다고 함수 CM를 초기화하여 x에 2가 들어갔다는 사실이 사라진다면 double에 5를 넣어도 결과값은 x * 5가 됐을 것이다.
때문에 클로저 기능이 없을 경우에 위와 같은 함수를 실행하려면 x, y 인수를 한번에 넣어야 했을 것이다.
1. 클로저(closure)는 의도적으로 넣어진 기능이다.
클로저(closure)는 이처럼 특정 상황에서 발생하는 문제들을 해결하고 개발자들에게 더 강력하고 유연한 도구를 제공하기 위해 의도적으로 도입한 기능이다.
1. 클로저의 특징 및 도입 이유
2. 1. 데이터 은닉 및 보호
- 함수 내에 변수를 정의하면 외부 코드가 내부에 정의된 변수에 접근 못한다.
- 때문에 외부에서 내부 함수가 사용하는 데이터에 접근 못하여 데이터를 보호할 수 있다.
- 이는 변수가 유지되는 스코프가 함수 내부의 스코프로 한정되기 때문이다.
2.1. 예시
function createCounter() {
let count = 0; // 외부에서 직접 접근할 수 없는 비공개 변수
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.decrement(); // 0
클릭하여 코드 복사
함수 내부에 선언된 변수는 일반적으로 외부에서 '직접 접근'이 불가능하다.
즉 함수가 참조한 변수가 let이나 var같은 변수처럼 재할당되어 함수의 동작이 바뀔 걱정이 없다는 것이다.
때문에 함수 내부의 데이터는 외부로부터 보호된다고 할 수 있다.
3. 2. 상태 유지:
- 외부 함수의 변수는 외부 함수가 실행된 최초에 1번만 입력 받기 때문에 입력된 변수를 계속 동일한 값으로 사용 할 수 있다.
- 이후 외부 함수 밖의 변수가 재할당 되어도 그것이 이미 입력된 변수에 영향을 끼치지 않는다.
- 하지만 내부 함수를 통해 해당 변수의 값을 변경하는 것은 가능하다.
function createCounter() {
let count = 0; // 외부에서 직접 접근할 수 없는 비공개 변수
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.decrement(); // 0
클릭하여 코드 복사
해당 예시에서 선언된 let count = 0;라는 함수는 지역 변수로서 해당 함수 내부(함수 스코프)에서만 유효하다.
때문에 함수 외부에서 해당 함수를 수정할 수 있는 방법은 전혀 없다. (내부에서는 재할당 같은 것이 가능하지만)
때문에 외부 함수를 호출할 때 어떠한 상황에서든 내부의 값이 변경되지 않아서 내부 함수가 언제나 동일하게 작동하게 된다.
4. 3. 함수 팩토리
- 함수 팩토리는 다른 함수를 생성하는 함수이다.
- 외부 함수 자체는 변수를 계속 받을 수 있기 때문에 외부 함수의 변수에 따라 달라지는 내부 함수를 만들 수 있다.
- 이를 사용해서 함수형 프로그래밍을 지원하고 모듈성 및 코드 재사용성을 향상 시킬 수 있다.
function multiplier(factor) {
return function(x) {
return x * factor;
};
}
const double = multiplier(2);
const triple = multiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
클릭하여 코드 복사
위 예시에서 multiplier 함수는 함수 팩토리이며, double과 triple은 multiplier 함수를 통해 생성된 함수다.
double과 triple 함수는 각각 2와 3을 곱하는 기능을 수행하며, 독립적으로 재사용될 수 있다.
실제 작용을 정리하면 factor라는 매개 변수에 각각 2와 3을 인수로 넣은 함수를 만든 것이다.
실제론 2x, 3x를 계산하는 함수가 만들어 진 것이다.
5. 4. 비동기 프로그래밍 및 콜백 함수:
- 클로저 자체가 비동기 작업을 수행하는 것은 아니지만, 비동기 작업의 콜백 함수에서 클로저를 사용한다.
- 클로저를 통해서 비동기 작업이 시작할 당시의 변수 상태를 기억하고 그 값을 사용할수 있기 때문이다.
'JavaScript > 자바 스크립트 기초' 카테고리의 다른 글
객체 지향 프로그래밍(OOP, Object-Oriented Programming) (0) | 2025.03.25 |
---|---|
얕은 비교, 깊은 비교 (0) | 2025.03.24 |
자바스크립트 이벤트 루프 / 동기와 비동기 (0) | 2025.03.24 |
이벤트 위임(Event Delegation) (0) | 2025.03.22 |
이벤트 버블링 (Event Bubbling)과 캡처링 (Event Capturing) (0) | 2025.03.21 |