클로저(Closure)란 무엇인가
클로저는 함수와 그 함수가 선언된 렉시컬 환경(Lexical Environment)의 조합이다. 간단하게 함수가 자신이 생성될 때의 환경(변수)을 기억하는 현상을 말한다.
클로저는 자바스크립트의 핵심 개념 중 하나로, 함수형 프로그래밍 패러다임과 다양한 디자인 패턴을 구현하는 데 필수적이다.
클로저는 단순히 내부 함수가 외부 변수에 접근하는 현상을 넘어, 자바스크립트의 렉시컬 스코핑 규칙과 실행 컨텍스트가 외부 환경 참조를 유지하는 방식의 자연스러운 결과이다. 외부 함수가 실행될때 생성된 실행 컨텍스트의 렉시컬 환경은, 그 내부에서 정의된 함수가 외부로 반환되거나 다른 곳에서 참조될 경우, 해당 내부 함수에 의해 계속 참조된다.
이 견결고리 때문에 외부 함수의 실행이 끝나도 관련 환경이 메모리에서 사라지지 않는 것이다. 모듈 패턴은 이러한 클로저의 특성을 활용한 대표적인 예시이다. IIFE나 일반 함수를 사용하여 '비공개' 스코프(외부 함수의 렉시컬 환경)을 만들고, 이 스코프에 접근할 수 있는 '공개'메서드(내부 함수)들을 객체 형태로 반환함으로써 데이터 캡슐화를 구현한다. 따라서 클로저를 실행 컨텍스트와 렉시컬 환경의 관점에서 이해하면, 그 작동 원리와 모듈 패턴과 같은 실제 활영 사례를 더 근본적으로 파악할 수 있다.
클로저가 발생하는 이유는 객체인 함수를 변수에 할당하면서 가능해 진다. 즉 객체로서 변수에 할당된 함수를 지속적으로 참조할 수 있는 것이다. 변수에 담지 않고 그저 함수를 사용하면 함수가 실행되고 사라지면 실행 컨텍스트도 같이 정리 되어야 하지만 변수는 남아 있기 때문에 해당 한수가 선언된 변수를 담고 있는 컨텍스트가 정리되기 전까지는 유지되는 것이다. 렉시컬 스코프 때문에 가능한 일
핵심 개념#
- 렉시컬 스코핑(Lexical Scoping): 함수가 선언된 위치에 따라 상위 스코프가 결정된다.
- 변수의 생존: 함수가 선언된 함수의 변수들이 함수가 호출될 때까지 메모리에 유지된다.
- 캡슐화(Encapsulation): 데이터와 그 데이터를 조작하는 마수를 하나의 단위로 묶는다.
JavaScriptjs
이 예제이서 createCounter
는 내부 함수를 반환한다. 내부 함수는 count
변수를 참조하고 있으며, 원래라면 createCounter
함수가 실행을 마치면 count
변수는 사라져야 하지만, 클로저 덕분에 내부 함수가 count
변수를 계속 기억하고 접근할 수 있다.
활용 사례#
-
데이터 은닉과 캡슐화 외부에서 직접 접근할 수 없는 비공개(private) 변수를 만들고, 오직 클로저를 통해 노출된 함수(메서드)를 통해서만 이 변수에 접근하거나 조작하도록 할 수 있다. 이는 객체 지향 프로그래밍의 캡슐화와 유사한 효과를 제공한다.
JavaScriptjs -
상태 유지 함수 호출이 끝나도 이전 상태를 기억하고 유지해야 할 때 사용된다. 예를 들어, 호출 될 때마다 1씩 증가하는 카운터를 만들 수 있다.
JavaScriptjs -
함수 팩토리 특정 설정을 가진 함수를 동적으로 생성할 때 사용된다. 외부 함수에서 설정값을 받고, 이를 기억하는 내부 함수를 반환하는 방식이다.
-
비동기 처리에서의 상태 관리 콜백 함수나 프로미스 핸들러 등 비동기 작업이 완료된 후 특정 컨텍스트나 상태를 참조해야할 때 클로저가 활용된다.
-
모듈 패턴 구현 전역 스코프를 오염시키지 않고 독립적인 모듈을 만드는 데 클로저가 핵심적인 역할을 한다.
클로저의 주의점#
-
메모리 관리 클로저는 참조하는 변수를 메모리에 계속 유지하므로, 불필요한 클로저는 메모리 누수의 원인이 될 수 있다. 더 이상 필요 없는 클로저나 클로저가 참조하는 변수에 대한 참조를 명시적으로 끊어줘야 한다.(변수에
null
할당) -
루프 내에서의 클로저 루프 안에서 비동기 함수를 사용할 때 예상치 못한 결과가 나올 수 있다. 이벤트 리스너 등은 사용이 끝나면 반드시
removeEventListener
등을 사용하여 제거해야 한다.