“A closure is the combination of a function and the lexical environment within which that function was declared.”
클로저란 함수와 그 함수가 선언된 렉시컬 환경의 조합이다.
자바스크립트에서 클로저는 단순히 “함수 안의 함수” 그 이상이다.
클로저는 함수가 만들어질 당시의 스코프를 기억하는 메커니즘으로, 자바스크립트의 스코프와 실행 컨텍스트 구조를 이해하는 데 핵심적인 개념이다.
1. 렉시컬 스코프 (Lexical Scope)
자바스크립트는 렉시컬 스코프(정적 스코프)를 따른다.
즉, “함수가 어디서 호출되었는가”가 아니라 “어디서 정의되었는가”에 따라 상위 스코프가 결정된다.
const x = 1;
function foo() {
const x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar는 전역에서 정의되었기 때문에, 상위 스코프는 전역이다.
따라서 foo 안에서 호출되더라도, bar는 전역 변수 x를 참조한다.
이때 각 스코프는 렉시컬 환경(Lexical Environment)으로 표현된다.
모든 렉시컬 환경은 자신의 외부 렉시컬 환경에 대한 참조(Outer Lexical Environment Reference)를 가진다.
이 참조들이 연결되어 스코프 체인(scope chain)을 이룬다.
2. 함수 객체의 [[Environment]] 내부 슬롯
모든 함수 객체는 내부 슬롯 [[Environment]]를 가지고 있으며,
이 안에 자신이 정의된 환경(상위 스코프에 대한 참조)을 저장한다.
즉, 함수가 정의될 때 이미 “나는 이 스코프 안에서 만들어졌어”라는 정보를 기억하는 것이다.
function outer() {
const x = 10;
function inner() {
console.log(x);
}
return inner;
}
inner 함수가 생성되는 시점에, [[Environment]] 내부 슬롯에는 outer 함수의 렉시컬 환경이 저장된다.
따라서 outer가 종료되어도 inner는 x를 기억할 수 있다.
3. 클로저의 실제 동작
const x = 1;
function outer() {
const x = 10;
const inner = function () {
console.log(x);
};
return inner;
}
// outer 실행 → inner 반환
const innerFunc = outer();
innerFunc(); // 10
실행 흐름
- outer()가 호출되면 새로운 렉시컬 환경이 생성되고,
- x = 10, inner가 정의된다.
- outer()의 실행이 끝나면 실행 컨텍스트는 스택에서 제거된다.
- 하지만 outer의 렉시컬 환경은 여전히 inner 함수의 [[Environment]] 내부 슬롯에서 참조되고 있다.
- innerFunc()를 호출하면
- console.log(x)가 실행되고, 이때의 x는 outer의 환경에 저장된 10을 참조한다.
즉, outer 함수는 이미 종료되었지만, 그 내부 변수 x는 inner 함수에 의해 기억되고 살아있는 상태다.
이것이 바로 클로저(closure)다.
4. 클로저의 정의와 의미
클로저란 외부 함수보다 더 오래 유지되는 중첩 함수로,
이미 생명주기가 끝난 외부 함수의 변수를 계속 참조할 수 있는 함수다.
클로저는 함수가 자신이 선언될 당시의 스코프를 기억하기 때문에,
호출되는 위치와 상관없이 언제나 그 스코프에 접근할 수 있다.
이때 클로저가 참조하는 외부 변수(예: x)를 자유 변수(free variable)라고 부른다.
즉, 클로저는 “자유 변수에 대해 닫혀 있다(closure)”는 의미에서 유래했다.
5. 가비지 컬렉션과 생존 이유
outer의 실행 컨텍스트는 종료되어 스택에서 제거되지만, outer의 렉시컬 환경 자체는 여전히 메모리에 남는다.
왜냐하면 inner 함수가 그 환경을 참조하고 있기 때문이다.
- outer의 렉시컬 환경 → inner.[[Environment]]가 참조
- inner 함수 → 전역 변수 innerFunc가 참조
- 따라서 가비지 컬렉션 대상이 되지 않는다.
이 덕분에 innerFunc()를 나중에 호출하더라도 outer의 변수에 접근할 수 있는 것이다.
6. 요약 및 마무리
개념 | 설명 |
렉시컬 스코프 | 함수가 정의된 위치에 따라 상위 스코프가 결정된다. |
[[Environment]] | 함수가 정의될 때 상위 스코프를 저장하는 내부 슬롯. |
자유 변수 (Free Variable) | 클로저가 외부 스코프에서 참조하는 변수. |
클로저 | 외부 함수보다 오래 살아남아 상위 스코프를 기억하는 함수. |
메모리 유지 | 클로저가 참조 중인 변수는 GC 대상에서 제외된다. |
클로저는 단순한 개념처럼 보이지만,
스코프, 실행 컨텍스트, 메모리 관리까지 아우르는 자바스크립트 핵심 메커니즘이다.
실무에서는 다음과 같은 상황에서 특히 유용하다.
- 상태를 은닉한 private 변수 구현
- 함수형 프로그래밍 패턴
- React 훅 내부 로직 (예: useState, useEffect 등)
이처럼 클로저를 이해하면, 자바스크립트의 스코프 관리와 실행 구조를 깊이 있게 이해할 수 있다.
'Frontend > Javascript Essentials' 카테고리의 다른 글
프로토타입 기반 상속 (0) | 2025.10.12 |
---|---|
이벤트 루프 (0) | 2025.10.11 |