Javascript - Closure
이번에는 Javascript를 보다 깊게 이해하기 위해서 꼭 이해해야 한다는 클로져(Closure)에 대해서 정리해 보고자 한다.
Javascript 에서의 '변수' 의 영역은 Global 과 local로 나뉜다.
var a; // Global variable
function func() {
var b; // Local variable
}
일반적으로 함수 외부에 선언된 전역(Global) 변수를 함수 내부에서는 사용할 수 있고, 함수 내부에 선언된 지역(Local) 변수를 함수 외부에서는 사용할 수 없지만 이를 위반하고 사용 가능하게 하는 것이 클로저(Closure) 이다.
클로저는 사용 후에 소멸되는 지역변수를 붙잡아 둔다.
만약, 우리가 어떠한 액션에 반응하여 특정 카운팅을 증가시켜야 할 때 보통 생각하는 방법은 전역 변수를 이용하는 방법이다.
var actionCnt = 0;
function increment() {
++actionCnt;
}
increment();
increment();
...
increment();
이 방법은 사실 별 문제가 없어 보이고 가독성도 크게 나쁘지 않다. 일반적인 케이스에서는 말이다. 하지만 Javascript 코드가 길어지고 다른 Action에 대한 카운팅 변수들이 필요할 때 전역변수들이 무분별하게 많아져 코드는 더러워지고 가독성도 나빠지게 된다. 그리고 전역 변수의 생명 주기(Life Cycle)는 우리의 어플리케이션 (Window or Web Page) 이 살아있는 동안 영원히 살아있기 때문에 지역 변수에 비해 메모리 활용면에서 확실히 떨어진다.
Closure
클로저는 이에 대한 단점을 해결해준다. 지역변수를 활용해서 말이다.
function increment() {
var actionCnt = 0;
function realIncrement() {
++actionCnt;
}
return realIncrement;
}
var incrementor = increment();
incrementor();
incrementor();
...
incrementor();
보통의 언어라면 말도 안되는 코드이다. 하지만 Javascript 에서 함수 내부에 선언된 함수는 자신이 선언된 '환경' 에 대해서 연결을 갖는다. MDN에 따르면 클로저는 '함수'와 '그 함수가 만들어진 환경' 이 두가지로 이루어진 특별한 객체라고 소개한다. 그 함수가 만들어진 환경은 함수가 만들어질 때 사용할 수 있었던 변수들로 이루어지는데 위와 같은 경우에 incrementor가 realIncrement 함수와 actionCnt 변수를 가진 클로저 인스턴스이다. incrementor 는 actionCnt 를 가지고 있기 때문에 incrementor() 가 호출될 때마다 actionCnt의 값이 1씩 증가하게 되는 코드이다.
다음과 같이 조금 더 간결하게 코드를 바꿀 수 있다.
var incrementor = (function () {
var actionCnt = 0;
return function () {
++actionCnt;
}
})();
incrementor();
incrementor();
Conclusion
사실, 아직 잘 모르겠다. 오늘 이해한 것은 클로저(Closure)란 아주 특별한 오브젝트이며 사용 방면이 다양하다는 점이다. 내가 소개한 예제의 클로저는 input 이 없는 클로저 였지만 input으로 같은 환경에서 다른 클로저를 만들 수도 있다. 하지만 클로저란 결국 함수 내부의 함수를 선언하는 형태로 꼭 필요한 곳이 아닌곳에 무분별하게 사용하면 분명히 성능 이슈가 발생할 것 같다.