Javascript - 클로저(Closure)에 대한 정리

November 18, 2017

javascript에서 늘 빠지지 않는 내용이라 한다면, 클로저(Closure)를 빼놓을 수 없을 것 같습니다. 클로저는 다양한 책과 블로그에서도 필수로 나와있는 내용이지만, 설명되어 있는 부분도 다를 뿐더러, 내용도 애매한 부분들이 많습니다.

클로저를 공부할때 정말 다양한 의미로 인해서 이해하기 힘든 부분들이 많았었는데요, 정리한 부분들을 중심으로 설명을 드릴까 합니다. 혹시 다른 내용이나 정리하신 부분들과 다른 내용들이 존재한다면, 말씀해 주시면 적극 반영하겠습니다.

많은 책과 블로그에서 설명되고 있는 클로져는 다음과 같은 내용으로 요약됩니다.

"외부함수가 종료되더라도, 외부함수의 변수들과 관계를 지속해서 사용할 수 있는 구조"

요약되는 내용은 이러하지만, 이를 어떻게 설명할 수 있는지가 애매한 부분들이 많습니다. 다음의 예제를 보겠습니다.

function outer () {
    var x = 0;
    return function () {
        return ++x;
    }
}
 
var x = -1;
var f = outer();
f();

클로저에 대한 함수입니다. 보시면, outer 함수에서는 내부의 x값을 사용한 이름없는 익명함수(anonymous)를 반환값으로 사용합니다. 첫번째 포스팅에서 저는 변수관리에 대한 스코프 체인 및 렉시컬 환경을 설명 드린바 있습니다.

위의 예제를 통한 렉시컬 환경에서의 스코프 체인은 다음과 같습니다. 스코프체인 설명

javascript 실행환경에서 var f = outer();가 실행되면, 외부 함수 내의 익명함수가 파싱단계에서 outer의 외부로 전달되어 실행이 됩니다.

이때의 return ++x;의 x값은 전역변수 객체의 x변수가 아닌, 앞서 설명드렸던 렉시컬(정의) 환경에서의 x를 사용하기 때문에, 외부함수 outer의 x값을 참조하게 됩니다.

이렇게 되면서 실행환경 후의 f() 값은 1이 됩니다. 이를 계속해서 호출해 봅니다.

f();
f();
f();
f();

이후의 값들은 계속해서 증가합니다.

2
3
4
5

이제부터 클로저에 대한 설명을 좀더 명확하게 드릴 수 있을것 같습니다. 이처럼 내부함수에서 선언된 변수가 아니면서 내부함수에서 사용하는 외부함수 outer의 x값자유 변수라고 합니다.

이때, 외부함수에서 사용하는 변수 x의 값은 outer호출이 종료되면, 메모리에서 제거 되는 것이 일반적입니다.

하지만, 위의 예제에서의 변수 x값이 메모리에서 제거되는 시기는 외부함수 outer가 종료됨에 따라 결정이 되지 못합니다. 이유는 var f = outer();를 통해 내부 함수가 외부환경으로 나오게 되는데, 이때 반환되는 익명함수는 외부함수의 변수 x를 참조하고 있기 때문에 변수 스코프는 outer가 실행되는 실행환경까지 확장하게 됩니다.

이렇게 되면서, outer()가 종료됨에도 불구하고, 외부 환경에서의 변수 f가 outer를 참조하고 있는 이상, outer함수는 x변수로 인해 계속해서 실행중의 상태에 놓이게 됩니다. 이를 통해 계속해서 외부함수 outer의 x값은 메모리에서 사라지지 않고, 사용 가능하게 됩니다.

설명을 토대로 다시한번 위에 설명되었던 클로저의 한줄 설명을 곱씹어 봅시다.
실행 환경에서 외부 함수 outer를 사용하는 변수를 통해 outer에서 반환되는 익명함수가 실행환경으로 유효범위가 확장하고, 익명함수가 정의되는 환경에서 사용하게 되는 outer함수 내의 변수 x를 계속해서 참조하고 있기 때문에, 외부함수 outer의 실행이 종료되더라도, 계속해서 외부함수 outer는 실행중 상태가 되어 메모리에는 outer의 변수와 스코프 관계를 유지할 수 있게됩니다.

이처럼, 클로져는 외부함수가 종료되더라도 그 함수의 변수 및 관계를 메모리에 유지할 수 있는 구조가 됩니다.

명확하게, 클로저에 대한 설명을 하고자 했습니다. 이에따른 클로저의 완성 조건은 다음과 같이 세가지로 요약할 수 있습니다.

  • 1) 내부함수가 익명함수로 되어 외부함수의 반환값으로 사용해야 합니다.
  • 2) 반환되는 내부함수는 외부함수의 실행환경에서 실행됩니다.
  • 3) 내부함수에서 사용하는 변수는 외부함수의 변수 스코프에 있어야 합니다.

다음과 같은 3가지 조건을 충족해야 클로저를 구성할 수 있습니다.

...