[javascript] 클로저 - 클로저란?

1 minute read

코어 자바스크립트 책에 있는 내용과 예제를 요약한 포스트입니다.

1. 클로저란?

클로저(closure)는 함수형 프로그래밍 언어에서 등장하는 보편적인 특성으로, MDN에서는 함수와 그 함수가 선언될 당시 lexical environment(outerEnvironmentReference)의 상호관계에 따른 현상 이라고 한다.

어떤 컨텍스트 A 에서 선언한 내부함수 B의 실행 컨텍스트가 활성화된 시점에서, A에서는 B에서 선언한 변수에 접근할 수 없지만 B는 outerEnvironmentReference 를 통해 A의 LexicalEnvrionment에 접근할 수 있다. - 외부 변수를 참조하는 경우에 한하여.

  • 외부 함수의 변수를 참조하는 내부 함수 (1)
    var outer = function(){
      var a = 1;
      var inner = function(){
          return ++a;
      };
      return inner();
    };
    var outer2 = outer();
    console.log(outer2);    // 2
    console.log(outer2);    // 2
    

함수의 실행결과를 리턴, outer 함수의 실행 컨텍스트가 종료된 시점에서는 a 를 참조하는 대상이 없어진다. a, inner 변수의 값은 가비지 컬렉터에 의해 소멸한다.

  • 외부 함수의 변수를 참조하는 내부 함수 (2)
var outer = function(){
    var a = 1;
    var inner = function(){
        return ++a;
    };
    return inner;   // 함수 자체를 반환
};
var outer2 = outer();
console.log(outer2());  // 2
console.log(outer2());  // 3

가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있으면 그 값은 수집 대상에 포함시키지 않는다. outer함수는 실행 종료 시점에 inner 함수를 반환하므로 outer의 실행이 종료되더라도 inner는 outer2를 실행함으로서 호출되므로, 가비지 컬렉터의 수집대상에서 제외되고 때문에 inner 함수가 변수에 접근할 수 있는 것이다.

이처럼 클로저란, 외부함수의 LexicalEnvironment가 가비지 컬렉팅 되지 않는 현상에 의해 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우, A의 실행 컨텍스트가 종료되어도 변수 a가 사라지지 않는 현상을 말한다.

  • return 없이 클로저가 발생하는 다양한 경우
// (1) setInterval/setTimeout
(function(){
    var a = 0;
    var intervalId = null;
    var inner = function(){
        if(++a >= 10){
            clearInterVal(intervalId);
        }
        console.log(a);
    }
    intervalId = setInterval(inner, 1000);
})();

(1)은 별도의 외부객체인 window의 메서드에 전달할 콜백 함수 내부에서 지역변수를 참조

// (2) eventListener
(function(){
    var count = 0;
    var button = document.createElement('button');
    button.innerText = 'click';
    button.addEventListener('click', function(){
        console.log(++count, 'times clicked');
    });
    document.body.appendChild(button);
})();

(2)는 별도의 외부객체인 DOM의 메서드(addEventListener)에 등록할 handler 함수 내부에서 지역변수를 참조.

둘 다 지역변수를 참조하는 내부함수를 외부에 전달했으므로 클로저다.

이처럼 외부전달이 return이 아닌 경우에도 발생할 수 있는 점에 주의하도록 한다.

Comments