[JavaScript] Closure

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. 루프 안에서 클로저를 활용할 때는 주의해야한다
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); // 4 4 4 4

위와 같은 코드는 코드가 실행될 때 이미 i의 값은 4가 되어있으므로 클로저를 실행할 때 4만 출력하게 된다.

클로저의 기본 개념은 쉬운거 같지만 활용 방안은 어려운 개념인거 같다. 두고두고 봐야겠다.

Author: Song Hayoung
Link: https://songhayoung.github.io/2020/07/14/Languages/JS/Closure/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.