코어 자바스크립트 05 | 클로저

01. 클로저란?

MDN(Mozilla Developer Network)에서는 클로저에 대해 "A closure is the combination of a function and the lexical environment within which that function was declared."라고 소개한다. 직역해보면, "클로저는 함수와 그 함수가 선언될 당시의 lexical environment의 상호관계에 따른 현상" 정도로 볼 수 있다.

01 var outer = function() {
02   var a = 1;
03   var inner = function() {
04      console.log(++a);
05   };
06   inner();
07 };
08 outer();

위의 코드를 보면

01번 줄 outer 함수 : 변수 a를 선언, outer의 내부함수인 inner 함수에서 a의 값을 1만큼 증가시킨 다음 출력한다.

03번 줄 inner 함수 : 여기서는 a를 선언하지 않았기 때문에, environmentRecord에서 값을 찾지 못한다. 따라서 outerEnvironmentReference에 지정된 상위 컨텍스트인 outer의 LexicalEnvironment에 접근해서 a를 찾는다.

이후, outer 함수의 실행 컨텍스트가 종료되면 LexicalEnvironment에 저장된 식별자들(a, inner)에 대한 참조를 지운다. 그리고 가비지 컬렉터의 수집대상이 된다.

01 var outer = function() {
02   var a = 1;              // 변수 a는 outer의 내부함수인 inner에서 사용된다.
03   var inner = function() {
04      console.log(++a);
05   };
06   return inner;
07 };
08 var outer2 = outer();
09 console.log(outer2());

조금 수정된 코드이다.

06번 줄에서 inner 함수의 실행 결과가 아닌 inner 함수 자체를 반환했다. 그러면 08번 줄에서 outer 함수의 실행 컨텍스트가 종료될 때 outer2 변수는 outer의 실행 결과인 inner 함수를 참조하게 될 것이다. 이후 09번 줄에서 outer2를 호출하면 return inner가 실행될 것이다.


그런데 이상한 점이 있다. inner 함수를 return하여 실행시키는 시점에 **outer 함수는 이미 실행 컨텍스트가 종료**되어 있을텐데, outer 함수의 내부함수인 inner 함수를 어떻게 실행할 수 있는 걸까?

outer2가 실행되면 inner 함수는 언제든 호출되어야 한다. 또한 inner 함수는 변수 a를 사용하고 있기 때문에, a와 inner 모두 가비지 컬렉터의 대상에서 제외된 것이다.
=> 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함시키지 않는다.

정리하자면,

클로저란 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상을 말한다.
이것은 어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상이다.
주의할 점은 '내부함수 B를 외부로 전달'이 return만을 의미하는 것은 아니다. 콜백으로 전달하는 경우도 있다.

02. 클로저와 메모리 관리

클로저는 어떤 필요에 의해 의도적으로 함수의 지역변수를 메모리를 소모하도록 함으로써 발생한다. 이 필요성이 사라진 시점에는 메모리를 소모하지 않도록 해야한다.
그 방법은 참조 카운트를 0으로 만드는 것이다. 식별자에 참조형이 아닌 기본형 데이터(null, undefined)를 할당하면 된다.

03. 클로저 활용 사례

1) 콜백 함수
2) 접근 권한 제어(정보 은닉)
3) 부분 적용 함수
4) 커링 함수

좋은 웹페이지 즐겨찾기