스노우보드 참 좋아하는데 맨날 키보드 앞에만 있네

[JavaScript] 클로저 (closure) 본문

개발/Javascript

[JavaScript] 클로저 (closure)

워너-비 2017. 10. 31. 11:14

<!-- 본 포스팅은 개인공부를 위한 용도로 잘못된 정보가 있을 수 있습니다. 오류 발견시 댓글 환영합니다. -->


클로저 (closure)





클로저란 무엇인가?


MDN에서 다음과 같이 정의하고 있다.


"A closure is the combination of a function and the lexical environment within which that function was declared."  


번역하면 "함수와 함수가 선언된 어휘적 환경의 조합" 이라는 말인데... 무슨소리인지 모르겠다.


보통 함수 내에서 함수를 정의하고, 사용하면 클로저라고 하는데, 그 외에도 정의는 다양하다. 아래의 예제를 통해 이해를 돕도록 하자



[1 단계]


1
2
3
4
5
6
7
8
9
var cnt = 0;
function increaseCnt(){
cnt++;
}
increaseCnt(); // cnt == 1
increaseCnt(); // cnt == 2
increaseCnt(); // cnt == 3

console.log(cnt);



함수 increaseCnt() 내부에서 전역 변수 cnt에 접근하며, 함수실행 후 cnt 값인 '3'을 콘솔창에 출력한다.



[2 단계]


1
2
3
4
5
6
7
8
9
function increaseCnt(){
var cnt = 0;
cnt++;

console.log(cnt);
 }
 increaseCnt(); // 1 출력
 increaseCnt(); // 1 출력
 increaseCnt(); // 1 출력



increaseCnt() 함수 내부에 cnt를 지역변수로 선언했으며, 연산과 콘솔창 출력을 하고, increaseCnt()를 3회 호출한 예제이다.

지역변수 cnt는 함수 increaseCnt()를 호출될때마다 0으로 초기화해주므로, 출력값은 순서대로 1 1 1 이다.



[3 단계] 어휘적 유효 범위


1
2
3
4
5
6
7
8
9
10
11
12
13
function closure(){
 var cnt = 0;
 
 function increaseCnt(){   // increaseCnt()는 내부함수이며, 클로저다.
 cnt++;
 console.log(cnt);
 }
 
 increaseCnt(); // 1 출력
 increaseCnt(); // 2 출력
 increaseCnt(); // 3 출력
 }
 closure();



어휘적 유효 범위란 소스 코드 내에서 변수가 선언된 위치를 사용하여 변수의 사용 가능한 범위를 말한다.


closure()은 지역변수 cnt와 함수 increaseCnt()를 생성한다.

increaseCnt()는 closure() 안에 정의된 내부함수이며, closure() 함수 본문에서만 사용할 수 있다.

내부함수는 외부함수에 선언된 변수들에 접근할 권한을 가진다.

따라서 내부함수 increaseCnt()는 부모 함수 closure()에서 선언된 변수 cnt에 접근할 수 있다.



[4 단계] 클로저


1
2
3
4
5
6
7
8
9
10
11
12
13
function closure() {
var cnt = 0;
  
return function increaseCnt() { 
cnt++
console.log(cnt);
};  
}
var increaseCnt = closure();
 
increaseCnt();
increaseCnt();
increaseCnt();

 


위 예제에서 내부함수 increaseCnt() 는 실행되기 전에 외부함수 closure 로부터 반환(return)된다.

대부분의 언어에서 함수 안의 지역 변수들은 그 함수가 수행되는 동안에만 존재하며, 위의 예제처럼 closure() 실행이 끝났을때는 cnt 변수에 더 이상 접근할 수 없는 것이 일반적이다그러나 자바스크립트는 예외다.


그 이유는 자바스크립트의 함수가 클로저를 형성하기 때문이다.

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 이 환경은 클로저가 생성된 시점의 범위 내에 있는 모든 지역 변수로 구성된다.

변수 increase는 closure가 실행될 때, 생성된 increaseCnt() 함수의 인스턴스를 참조한다.

increaseCnt()의 인스턴스는 그 변수, cnt가 있는 어휘적 환경에 대한 참조를 유지한다. 따라서 increaseCnt()가 호출될 때, 변수 cnt는 사용할 수 있는 상태로 남게되며, 콘솔창에 출력이 가능한 것이다.



다른 클로저 예를 알아보자


1
2
3
4
5
6
7
8
9
10
11
function closure(x){
return function(y){
return x+y;
};
}
 
var add5 = closure(5);
var add10 = closure(10);
 
console.log(add5(2));    // 7
console.log(add10(2));  // 12




단일인자 x를 받아 함수를 반환하는 closer(x)를 정의했다. 반환되는 익명함수는 단일인자 y를 받아 x+y를 반환한다.


위의 예제에서 두 개의 새로운 함수를 생성하기 위해 함수 팩토리를 사용한다.

closure(x)가 함수 팩토리다. (함수 팩토리 : 특정한 값을 함수의 인자에 덧붙일 수 있는 함수를 생성)

하나는 원래 인자에 5를 더하고, 다른 하나는 원래 인자에 10을 더한다.


add5, add10 모두 클로저다.

같은 함수의 정의를 공유하지만, 서로 다른 데이터를 저장한다. add5 는 문법적 환경에서 x==5 이지만, add10 는 x==10 이다.



출처 : MDN web docs


Comments