Closure
클로저란 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수이다.
1 2 3 4 5 6 7 8
| function outerFunc() { var x = 10; var innerFunc = function() {console.log(x);} return innerFunc; }
var inner = outerFunc(); inner();
|
위와 같이 outerFunc 컨텍스트의 생명 주기는 끝이 났지만 inner()를 통해서 outerFunc의 변수인 x를 참조하고 있다.
클로저의 활용
특정 함수에 사용자가 정의한 객체의 메서드 연결
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function Hellofunc() { this.greeting = "hello"; } Hellofunc.prototype.call = function(func) { func ? func(this.greeting) : this.func(this.greeting); }
var userFunc = function(greeting) { console.log(greeting); }
var objhello = new Hellofunc(); objhello.func = userFunc; objhello.call();
|
위와 같이 Hellofunc에서 greeting을 정의하고 call 메소드를 재정의한 뒤 userFunc를 오브젝트의 func으로 등록해서 메서드를 연결시킨다.
함수의 캡슐화
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var getCompletedStr = (function() { var buffAr = [ 'I am ', '', '.', ];
return ((function(name) { buffAr[1] = name;
return buffAr.join(''); })); })();
var str = getCompletedStr('song'); console.log(str);
|
위와 같이 사용하고자 하는 변수를 함수 안에 캡슐화 하여 전역에서의 접근 방지나 이름에 의한 충돌을 방지할 수 있다.
setTimeout()에 지정되는 함수의 사용자 정의
1 2 3 4 5 6 7 8 9 10 11 12 13
| function callLater(obj, a, b) { return (function() { obj["sum"] = a + b; console.log(obj["sum"]); }); }
var sumObj = { sum : 0 }
var func = callLater(sumObj, 1, 2); setTimeout(func, 500);
|
setTimeout에 함수를 매개변수와 함께 넘기는 방법이다. callLater는 클로저를 리턴한다.
주의사항
- 클로저의 프로퍼티 값이 쓰기 가능하므로 그 값이 여러 번 호출로 항상 변할 수 있다
- 하나의 클로저가 여러 함수 객체의 스코프 체인에 들어가는 경우도 있다
- 루프 안에서 클로저를 활용할 때는 주의해야한다
1 2 3 4 5 6 7 8
| function countSeconds(howMany) { for (var i = 1; i <= howMany; i++) { setTimeout(function() { console.log(i); }, i * 1000); } }; countSeconds(3);
|
위와 같은 코드는 코드가 실행될 때 이미 i의 값은 4가 되어있으므로 클로저를 실행할 때 4만 출력하게 된다.
클로저의 기본 개념은 쉬운거 같지만 활용 방안은 어려운 개념인거 같다. 두고두고 봐야겠다.