본문 바로가기

Javascript

[JS] 클로저(closure)

728x90
반응형

내부 함수

function outter() {

var title = 'hello world';

function inner() { // var inner = function() {...} 와 같음

alert(title);

}

inner();

}


outter 함수에는 지역 변수 title과 내부 함수 inner가 정의되어 있습니다.

  • 내부함수는 외부함수의 지역변수에 접근할 수 있습니다.
    inner() 내부함수에 title이라는 변수가 없으면 외부함수의 지역변수인 title을 출력합니다.


내부함수를 왜 쓸까?

  • 어떤 함수에서만 사용하고싶은 함수를 정의하기 위해 사용합니다.
    outter()에서만 쓰고싶은 inner() 함수를 정의하고 싶은데 outter 밖에서 선언할 경우 다른 코드에서 inner() 를 사용할 수 있습니다.
    응집성을 높이고 다른 코드가 접근하는 상황을 막기 위해 내부에 정의합니다.


클로저

  • 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것
    (=> 내부함수는 외부함수의 지역변수에 접근이 가능)
  • 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근 가능

첫 번째 특징은 내부 함수를 설명하면서 이해할 수 있습니다.
두 번째의 특징의 예를 코드로 확인해보겠습니다.

function outter() {
 var title = 'hello world';
return function() {
alert(title);
}
}
var inner = outter();
inner();


outter 함수가 실행되어 return문을 만나면 함수가 종료 됩니다.

위 코드에서는 함수가 return 되었는데 리턴된 함수에서는 외부 함수에 있는 지역 변수인 title이 사용되었습니다.

프로그래밍적으로 생각해보았을 때 var inner = outter(); 부분을 실행하고나면

outter 함수가 종료되었기 때문에 이 함수의 지역변수는 소멸되고, inner에는 아무것도 들어가있지 않을거라고 예상할 수 있습니다.


하지만 실행시켜보면 'hello world' 가 출력됩니다. 외부 함수의 지역변수인 title이 소멸되지 않았다는 것을 의미합니다.


클로저란 내부함수가 외부함수의 지역변수에 접근할 수 있고,

외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 소멸되지 않는 특성을 의미합니다.




클로저의 활용, private 변수

function factory_movie(title){
return {
get_title : function (){
return title;
},
set_title : function(_title){
title = _title
}
}
}
ghost = factory_movie('Ghost in the shell');
matrix = factory_movie('Matrix');
alert(ghost.get_title());
alert(matrix.get_title());
ghost.set_title('공각기동대');
alert(ghost.get_title());
alert(matrix.get_title());


위 예제에서 factory_movie 함수의 반환 값은 객체 입니다.

반환 값의 객체의 메소드로 정의되어있습니다. 이 메소드도 외부 함수인 factory_movie의 내부 함수입니다.

내부 함수에서 title을 사용하는데 이 title은 외부 함수의 파라미터, 즉 외부 함수의 지역 변수를 사용합니다.

즉, 내부 함수에서 외부 함수의 지역 변수를 접근하고 있는 모습을 의미하는 클로저의 개념이 private 변수를 만드는데에도 활용됩니다.


클로저를 통해 private 변수인 title을 만듦으로써 외부에서는 title을 임의로 수정할 수 없고 get, set 메서드를 통해서 이용할 수 있습니다.

set 메서드를 사용해서 title을 바꾸려고 할 때, 내부적으로 변수를 다시 셋팅할 수 있는지 검사할 수 있기 때문에(ex. title이 문자열인지 검사) 더 안전하게 변수를 수정할 수 있습니다.





클로저의 예제

var arr = []

for (var i=0; i<5; i++) {

arr[i] = function() {

return i;

}

}

for (var index in arr) {

console.log(arr[index]());

}

위 예제는 0,1,2,3,4로 증가하는 i를 리턴하여 배열에 담기 위해 작성한 코드 입니다.

하지만 결과는 5 5 5 5 5 가 출력됩니다.


코드가 잘 동작하도록 고쳐보겠습니다.

var arr = []

for (var i=0; i<5; i++) {

arr[i] = function(id) { // 외부 함수

return function() { // 내부 함수

return id;

}

}(i);

}

for (var index in arr) {

console.log(arr[index]());

}

결과는 0 1 2 3 4 로 원하는대로 잘 동작합니다.


첫번째 예제에서 arr배열에 담기는 내용은

함수가 정의한 시점에서의 i값을 리턴하는 내용이 닮깁니다. 즉 그 시점에서의 i값은 for문에서 사용된 i값이죠.

결과적으로 for문이 다 돌고다면 i는 5가 되며 이후에 배열에 담긴 함수를 호출하면 i는 항상 5만 출력할 수 밖에 없게 됩니다.


두번째 예제에서 클로저를 이용했습니다.

현재 정의된 함수를 내부 함수로 하는 외부 함수를 정의하고, 내부 함수에서 외부 함수의 지역 변수를 사용하도록 합니다.

파라미터로 들어오는 i값이 id인 지역 변수로 적용되고 지역 변수를 내부 함수에서 리턴하기 때문에 원하는 결과 값을 얻을 수 있습니다.






생활코딩 - Javascript (클로저)

728x90
반응형