🪴 정의
클로저(Closure)란,
어떤 함수가 렉시컬 스코프를 기억하여 외부 함수의 실행이 종료된 후에도 내부 함수가 외부 변수에 접근할 수 있는 자바스크립트의 특성을 의미합니다.
즉, 외부 함수가 이미 종료되었음에도 불구하고 내부 함수가 외부 함수의 지역 변수에 접근할 수 있는 현상입니다.
이때 렉시컬 스코프란, 함수가 어디에서 선언되었는지에 따라 결정되는 스코프로,
함수가 실행되는 시점이 아니라 정의된 시점의 상위 스코프를 기억하는 특성을 의미합니다.
실무나 문서에서는 종종 '외부 변수에 접근할 수 있는 내부 함수'를 클로저라고 부르기도 합니다.
그러나 이는 해당 함수가 클로저를 갖고 있기 때문이며 엄밀히 말하면 클로저는 특정 함수 자체라기보다는
함수가 렉시컬 스코프를 기억하고 외부 변수에 접근할 수 있는 현상을 가리키는 개념입니다.
이러한 특성으로 인해 클로저는 데이터 은닉, 카운터 구현, 상태 유지와 같은 상황에서 주로 활용됩니다.
🪴 예시 코드
예를 들어, 아래의 코드에서는
내부 함수 inner가 -> 외부 함수 outer의 변수(지역 변수)인 counter에 접근할 수 있습니다.
function outer() {
let count = 0;
return function inner() {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1 출력
counter(); // 2 출력
아래에서 코드를 자세히 살펴보겠습니다.
🪴 코드 설명
1) outer 함수 호출
const counter = outer();
/**
function outer() {
let count = 0;
return function inner() {...};
}
**/
- outer 함수가 실행되면 내부에서 count라는 지역 변수가 선언되고 0으로 초기화됩니다.
- 함수의 실행이 끝나면 내부 함수인 inner 함수를 리턴합니다.
- 이때 리턴되는 inner 함수는 단순히 함수의 정의만 리턴되는 것이 아니라, count가 선언될 때의 환경(스코프)도 함께 기억한 상태로 리턴됩니다.
- 그리고 리턴된 내부 함수(inner 함수)는 counter라는 이름으로 저장됩니다.
2) 첫 번째 counter 함수 호출
counter(); // 1 출력
/**
function inner() {
count++;
console.log(count);
}
**/
- counter 함수 호출하면 inner 함수가 실행됩니다.
- inner 함수는 count++를 실행하고, count 변수의 값은 1이 됩니다.
- 이후 console.log(count)가 실행되어 1이 출력됩니다.
이때 count는 outer 함수의 지역 변수지만, inner 함수는 outer 함수의 실행이 끝나도 여전히 count에 접근할 수 있습니다.
이러한 현상을 클로저라고 하며, 내부 함수가 외부 스코프(렉시컬 스코프)를 기억하고 있기 때문에 발생하는 현상입니다.
3) 두 번째 counter 함수 호출
counter(); // 2 출력
/**
function inner() {
count++;
console.log(count);
}
**/
- 2번 코드 설명과 마찬가지로 counter 함수 호출하면 inner 함수가 실행됩니다.
- 그러나 이때 count 변수는 여전히 살아있고, 새롭게 선언되지 않습니다.
- 따라서 inner 함수는 count++를 실행하고, count 변수의 값은 2가 됩니다.
- 이후 console.log(count)가 실행되어 2가 출력됩니다.
🪴 정리
예시 코드에서 보았듯이, outer 함수의 실행은 끝났지만 내부 함수인 inner 함수가 count를 참조하고 있기 때문에
자바스크립트는 count가 선언된 렉시컬 스코프를 메모리에서 제거하지 않습니다.
이처럼 함수가 선언 당시의 외부 스코프를 기억하여 외부 함수의 지역 변수에 접근할 수 있는 현상이 바로 클로저입니다.
클로저는 값을 지속해서 기억할 수 있는 특성을 활용해 상태 유지, 카운터 구현, 데이터 은닉 등의 상황에 자주 사용됩니다.
읽어주셔서 감사합니다:)