클로저란 무엇인가?
클로저를 아시나요? 클로저는 함수형 프로그래밍 언어에서 등장하는 보편적인 특성입니다. 즉 자바스크립트 뿐 아니라 다른 프로그래밍 언어에서도 함수형 프로그래밍을 구현할 때 등장하죠. 클로저에 대한 정의는 다양한 문헌에서 등장하지만 하나같이 어렵기로 유명하죠.
-
자신을 내포하는 함수의 컨텍스트에 접근할 수 있는 함수
-
함수 특정 스코프에 접근할 수 있도록 의도적으로 그 스코프에서 정의하는 것
-
함수를 선언할 때 만들어지는 유효범위가 사라진 후에도 호출할 수 있는 함수
-
이미 생명 주기상 끝난 외부 함수의 변수를 참조하는 함수
-
자유변수가 있는 함수와 자유변수를 알 수 있는 환경의 결합
-
로컬 변수를 참조하고 있는 함수 내의 함수
-
자신이 생성될 때의 스코프에서 알 수 있었던 변수들 중 언젠가 자신이 실행될 때 사용할 변수들만 기억하여 유지시키는 함수
클로저 예시
정의로 설명하면 위처럼 어렵기 때문에 직접 코드를 보면서 예시를 살펴보겠습니다.
var outer = function () {
var a = 1;
var inner = function () {
return ++a
}
return inner
};
var outer2 = outer()
console.logI(outer2()) //2가 출력됨
예시의 코드에서 내부 함수인 inner가 return 값이 되면서 외부 변수에 할당됩니다. 그런데 inner 내부에 outer의 a 변수에 접근해야 하는 구조이죠. 이 때 outer 함수가 이미 종료되었더라도 outer2가 inner를 직접 할당 받기 때문에 outer의 a 값은 가비지 콜랙터로 들어가지 않고 살아있어야 합니다. 그래야 inner함수에서 사용할 수 있는 것이죠. 즉, 클로저의 정의를 다시 하자면
어떤 함수 outer에서 선언한 변수 a를 참조하는 내부함수 inner를 외부로 전달하면 outer의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상
이라고 할 수 있습니다. 한가지 더 챙겨야 할 점은 꼭 return 뿐 아니라 내부 함수에서 어떤 식으로든 outer의 지역변수를 참조하면 클로저가 발동한다는 것입니다.
클로저 메모리 해제
큰 부하는 아니지만 클로저를 살려두면 소모하는 메모리가 있는 문제가 있죠. 때문에 클로저를 해제하고 싶을 때 해제하는 기능을 알아둬야 합니다. 이를 위해서 의도적으로 참조 카운트를 0으로 만들어 줘야 하죠. 대표적인 방식으론 null, undefined를 할당해주는 방법이 있습니다.
var outer = function () {
var a = 1;
var inner = function () {
return ++a
// inner = null
}
return inner
};
var outer2 = outer()
console.logI(outer2())
// outer = null
위 같이 식별자의 함수 참조를 끊어주는 겁니다. 그러면 참조 카운트가 0가 되면서 모든 변수 요소는 가비지 콜렉팅의 대상이 됩니다.
접근 권한 제어 (정보 은닉)
마지막으로 접근 권한 제어입니다. 정보 은닉은 모둘 내부 로직에 대해 외부로의 노출을 최소화해 모듈간 결합도를 낮추고 유연성을 높이는 요소입니다. 흔히 접근 권한에는
- public
- private
- protect
이렇게 3가지로 나눌 수 있죠. public은 외부접근이 가능하고, private은 내부에서만 사용 가능하며 외부로 노출되지 않습니다. 자바스크립트는 기본적으로 변수자체에 이러한 접근 권한을 부여하도록 설계돼 있지 않습니다. 그러나 클로저를 이용하면 public한 값과 private 값을 구분 할 수 있죠. 어떤 식으로 구분해 주는지 볼까요?
var outer = function() {
var a = 1;
var inner = function(){
return ++a;
}
return inner
}
var outer2 = outer()
위 코드에서 outer는 외부와 격리된 독립적인 공간입니다. 다만 return을 통해 inner 함수를 제공해 inner만이 외부와 소통이 가능하죠. closure란 이름은 ‘닫혀있음’, ‘폐쇄성’을 나타냅니다. outer 함수 같이 외부와 격리된 요소들은 이렇게 폐쇄적이고 private한 값이죠. 그러나 return을 통해 외부와 연결된 inner는 public한 값입니다. 즉 클로저는 return 값을 통해 변수들을 공개값으로 설정하거나 return과 연관 없는 값들을 비공개 값으로 설정해줍니다. 이렇게 return을 통해 접근을 제어할 수 있는 거죠.