사전적으로 클로저는 외부함수(포함하고 있는)의 변수에 접근할 수 있는 내부 함수를 말한다. 클로저라는게 사실 유효 범위를 뜻하는 것이라 사실 우리가 알게 모르게 쓰고 있다. 자바스크립트를 어느정도 하는 사람은 아래 예제가 어렵지는 않을 것이다.
var num = 1;
function init(){
var num = 2;
return num;
}
console.log(init())//2;
자바스크립트가 변수를 찾아 나갈때는 유효범위의 우선 순위대로 찾아 나간다. init함수에서 num이라는 변수를 찾을 때, 가장 가까이 변수가 선언된 곳은 var num=2이므로 해당 값을 반환한다.
비슷 하지만 다음 예제를 보자.
var num = 1;
function init(){
var num = 2;
function getNum(){
return num;
}
return getNum;
}
console.log(init()())//2;
첫번째 예제와 거의 흡사하지만, 리턴을 변수가 아닌 함수로 넘겼다. 따라서 init()() 라는 조금 특이한 형태로 호출했다. init라는 함수를 호출해서 리턴받은 함수를 다시 호출한 것이다. 이 부분이 제일 중요한데, 왜냐하면 내부 함수(getNum)를 해당 내부함수의 외부함수(init)가 아닌 전역 영역에서 호출했다는 것이다. 또 호출된 내부 함수(getNum)의 유효범위가, 전역 영역에서 호출되었으메도 불구하고, 외부함수(init) 안의 변수에 접근해서 값을 가져왔다는 것이다.
외부함수(init)가 호출되고 함수의 해석이 끝날때, 리턴된 값이 함수로 남아 있어서 해당 함수에 접근할 수 있다면, 외부함수의 변수들은 사라지지 않고 남아있다고 한다. 그리고 자바스크립트의 유효범위는 함수가 호출될 때가 아닌, 정의될 때를 기준으로 작동된다고 한다.
이 개념을 잘 이해하고 있으면 다양한 방법으로 사용이 가능하다. 간단한 예제로, 숫자를 1씩 더하는 함수를 만들어 보자. 우리가 보통 사용하는 방법은 아래와 같다.
var num = 0;
function inc(){
num++;
return num;
}
console.log(inc());//1
console.log(inc());//2
console.log(inc());//3
함수안에 변수를 선언하면 함수가 실행될때 마다 변수가 초기화 되므로 전역 영역에 변수를 정의한다. 하지만 전역 영역에 변수를 정의하고 사용하는 것은 퍼포먼스를 고려할때 좋은 방법이 아니다.
이를 클로저를 사용하면 다음과 같이 바꿀수 있다.
function inc(){
var cnt = 0;
return function(){
cnt++;
return cnt;
};
};
var incFn = inc();
console.log(incFn());//1
console.log(incFn());//2
console.log(incFn());//3
실제로 사용해보니, 개인적으로는 엘리먼트 요소를 외부 함수에 미리 정의해두고, 내부함수에 접근해서 외부함수의 엘리먼트를 호출하는 형태를 많이 쓰게 되었다. 함수가 호출될때마다 엘리먼트를 찾지 않아도 되니 퍼포먼스 측면에서 효율적이었다.
댓글 없음:
댓글 쓰기