1 2 3 4 5 7 8 9 |
function closureTest(a){ return function(b){ return a + b; } } var test = closureTest(1); alert(test(2)); |
위의 예제를 실행하면 "3"이라는 메시지가 출력된다. 참고로 closureTest 함수에서 a 변수는 지역 변수이다.
1 2 3 4 5 6 8 9 10 |
function closureTest(a){ var a2 = a; return function(b){ return a2 + b; } } var test = closureTest(1); alert(test(2)); |
closureTest()에 "1"을 인수로 설정하여 실행하면 함수 내부는 다음 그림과 같이 동작한다.
closureTest()를 생성하면서 인수로 "1"을 지정하면 중첩 함수인 클로저는 그 값을 참조한다.
따라서 최종적인 클로저는 '인수로 받은 b에 기존에 포인터로 가지고 있던 "1"을 더해서 반환하는 함수'이다.
이제 test(2)를 실행하면 다음과 같이 동작한다.
따라서 test(2)는 최종 결과로 "3"을 출력하며 이 예제에서 중요한 것은 참조이다.
즉, 값 자체를 복사하는 것이 아니라 값을 참조하고 있으므로 참조하는 값이 바뀌면 참조하고 있던 값도 함께 바뀌게 된다.
심화
지금까지의 설명을 들어도 클로저 개념이 어렵게 느껴질 수도 있는데, 이해를 돕기 위해 비유를 해서 설명을 하자면 클로저는 C언어에서 "&" 키워드를 사용하여 정의하는 참조 변수라고 생각하면 된다. 단지 표현 방법의 차이가 있을 뿐, 실제 개념은 비슷하다고 보면 된다.
그럼, 아래 예제를 보도록 하자. (예제 링크)
1
2
3
4
5
6
7
8
9
10
11function plus() {
var i = 1;
return function(){
alert(i++);
};
}
var p = plus();
$("#but").click(function() {
p();
});
위의 예제를 보면서 문득 떠오른 것이 있다. 그것은 바로 OOP의 클래스 개념이다.
예전에 연재 했던 JS Tip & Tech (1) - OOP 기초 편을 보면 자바스크립트에서 함수는 OOP에서 클래스와 비슷하다고 설명한 적이 있다. 함수가 클래스와 비슷하다면, plus 함수 안에 선언된 "i"는 단순히 함수 안에서 사용되는 지역 변수가 아닌 클래스 맴버가 되기도 한다.
즉, 지역 변수 "i"의 호출 방식은 "By Value"가 아닌 "By Reference"가 될 수도 있다는 것을 의미한다. 우리가 이때까지 클로저 개념에 대해 이해하기가 어려웠던 이유는 자바스크립트에서 클래스라는 존재는 단순한 함수 정의와 다르지 않기 때문이다.
1
2
4
5
6
7
8
9
10
11
12var plus = new function() {
var i = 1;
this.add = function() {
alert(i++);
};
}
$("#but").click(function() {
plus.add();
});
위의 예제는 "new" 연산자를 사용하여 plus 함수를 객체화하였기 때문에 지역 변수 "i" 값을 plus 함수(클래스)의 맴버로써 참조할 수 있는 것이다.
그럼, 추가적으로 클로저에 대한 이해를 돕기 위해 다음 예제를 보도록 하자. (예제 링크)
1
2
4
5
6
7
8
10
11
12
14
15
16
18
19
20
21
22
24
25function buildList(list) {
var result = [];
for(var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
for(var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
예제의 출력 값이 "item1 1", "item2 2", "item3 3"으로 출력될 것으로 예상하였다면 클로저를 아직 이해하지 못한 것이다.
7라인에서 item과 list[i] 값은 result 배열에 push 될 때, 값 자체가 복사되서 들어가는 것이 아니라 참조되어 들어가기 때문에 "i"의 최종 값인 "3"으로 저장된다. 그렇기 때문에 출력 값은 "item3 undefined"가 된다.
그럼, 우리가 의도하고 있는 값을 출력하기 위한 아래 예제를 보자. (예제 링크)
1
2
4
5
6
7
8
9
10
12
13
14
16
17
18
20
21
22
23
24
26
27function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
(function(ii) {
var item = 'item' + list[ii];
result.push( function() {alert(item + ' ' + list[ii])} );
})(i);
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
익명 함수를 사용하여 간단하게 해결 할 수 있다. 그럼, 6라인과 9라인을 보도록 하자.
"i"의 값을 익명 함수의 매개변수로 넘겨 "ii" 인자 변수로 받음으로써 "i" 변수의 참조에서 벗어날 수 있게 되었다.
[ 출처 ] http://blog.naver.com/seogi1004/110120770472
추가 참고 : 클로저 개념 1
MDN : https://developer.mozilla.org/ko/docs/JavaScript/Guide/Closures
'JavaScript' 카테고리의 다른 글
[JavaScript] 유니코드 > 인코딩, 디코딩 (0) | 2012.12.13 |
---|---|
[JavaScript] 선택일 기준으로 월~토 일자 가져오기 (0) | 2012.10.22 |
[JavaScript] 네이버 지도 API 연동 (0) | 2012.08.14 |
[JavaScript] SNS 연동 (0) | 2012.08.14 |
[JavaScript] 숫자 3자리수마다 콤마 표시 (0) | 2012.05.07 |