클로저
클로저란 외부함수(포함하고 있는)의 변수에 접근할 수 있는 내부 함수를 말한다.
1 | function outer(){ |
여기서 outer()는 외부함수, inner()는 내부함수가 된다.
또한 변수 hello는 외부함수 outer()의 지역변수가 된다.
내부함수 innner()에서 외부함수 outer()의 hello의 지역변수에 접근할 수 있다. 이를 클로저라고 한다.
내부함수는 외부함수의 변수뿐만이 아니라 파라미터도 접근 가능하다.
1 | function outer(name){ |
클로저의 특징
클로저는 외부함수가 리턴된 이후에도 외부함수의 변수에 접근할수 있다.
내부함수는 외부함수의 지역변수에 접근 할 수 있다고 했는데, 특이한 점은 외부함수의 실행이 끝나서 외부함수가 return 된 이후에도 내부함수에서 외부함수 변수에 접근 할 수 있다는 것이다.
1 | function outer(){ |
위 예제를 보면 7행에서 외부함수 outer()를 호출해 변수 inner에 담았다.
그리고 outer는 익명함수를 return 한다. 그리고 8행에서 inner()를 호출하면, outer()는 실행이 끝났기 때문에(return) 소멸하고 외부함수의 지역변수 역시 소멸해야 한다. 하지만 8행에서 함수 inner를 실행했을때 “hi” 가 출력되었다는 것은 외부함수 outer의 지역변수 hello가 소멸되지 않았다는 것을 의미한다.
클로저는 외부함수의 지역변수를 사용하는 내부함수가 소멸되기 전까지 외부함수가 소멸되지 않게 한다.
동일한 외부함수 안에서 만들어진 내부함수나 메소드는 외부함수의 지역변수를 공유한다.
그리고 이러한 특성을 이용해 Private한 속성을 사용할 수 있게 한다.
1 | function movie(title){ |
1) 클로저는 객체의 메소드에서도 사용할 수 있다. 위 예제에서 외부함수 movie()의 return 값 안에 있는 get_title과 set_title 메소드는 movie()의 파라미터 값으로 전달된 지역변수 title의 값을 참조할 수 있다. (지역변수 공유)
2) 그러나 똑같은 외부함수 movie()를 공유하고 있는 blood와 joker의 get_title 결과와 set_title결과는 서로 다르다. 그 것은 외부함수가 실행 될 때마다 새로운 지역변수를 포함하는 클로저가 생성되므로 blood와 joker는 서로 완전히 독립된다.
3) 그러므로 , 26행에서 blood의 title을 변경했다고 해서 jocker의 title에 영향을 미치지 못한다.
4) movie()의 지역변수 title은 movie()의 리턴 값에서 정의된 메서드인 get_title과 set_title에 의해서만 접근할 수 있다. title이란 변수를 아무나 수정할 수 없고, 외부에서 title을 다르게 사용한다고 해서 이 함수에 영향을 미치지 못하게 된다.
private 속성은 객체 외부에서 접근할 수 없는 감춰진 속성을 말한다. javascript는 기본적으로 private한 속성을 지원하지 않지만, 클로저의 특성을 이용해서 private 한 속성을 사용할 수 있게 한다.
클로저를 통해 문제 해결하기
1 | var arr = []; |
위 예제는 반복문이 0부터 4까지 총 다섯번을 돌면서 i 값을 arr 란 배열에 저장하고, 이를 다시 콘솔에 찍는 예제이다.
위 예제의 결과를 0,1,2,3,4가 나온다고 기대할 수 있지만,
실제로 값을 찍어보면 5가 다섯 번 나오게 된다.
우선, 클로저는 내부 함수가 외부 함수의 지역변수를 참조 할 수 있는 것이라고 햇는데 , 여기서 var i 는 함수 레벨 스코프 단위로 감싸지는 전역변수가 된다. 즉 지역변수가 되지 못한다.
또한, arr[i]에 저장되는 값은 i값이 아닌
function(){
return i;
}
즉 함수 자체가 된다.
arr[0] = function(){
return i; //5
}
arr[1] = function(){
return i; //5
}
…
그리고 return 할때는 이미 반복문이 실행되어 i의 값이 5까지 올라간 상태가된다. 따라서 5가 5번 찍히는 것이다.
이 문제를 클로저를 통해 해결할 수 있다.
1 | var arr = [] |
마찬가지로 arr[i]는
function(id) { //외부함수
return function(){ //내부함수
return id;
}
}(i); //매개변수로 i를 줌
의 값을 받는다. 여기서 외부함수의 매개변수로 i를 주고 외부함수는 id라고하는 매개변수(지역변수)를 갖게 된다. 그리고 내부함수(클로저)는 외부함수의 지역변수를 참조할 수 있으므로 외부함수 id 값을 참조하게 된다. 그 함수가 만들어지게 되는 시점에 i 값을 id라는 매개변수로 받고 이를 내부함수가 그 값을 참조할 수 있으므로 우리가 원하는 결과를 찍게 된다.
참고 링크
자바스크립트 클로저 쉽게 이해하기 : http://chanlee.github.io/2013/12/10/understand-javascript-closure/