자 먼저 가장 흔한 예제로 시작해보자..
var arr = []
for (var i = 0; i < 5; i++){
arr[i] = function(){
return i;
}
}
for (var j = 0; j<arr.length ;j++){
console.log( arr[i]() );
}
이 예제는 무엇을 리턴할까? 원래 의도는 각각의 인덱스 0,1,2,3,4 를 리턴하는 함수를 각각의 인덱스의 값으로 저장하고 싶었지만 함수들을 실행한 결과는 5,5,5,5,5 로 모두 같은 i값을 출력하게 된다.
왜일까?
문제는 var로 선언된 i 가 '전역변수' 라는 것에 있다.
모두 같은 i 를 참조하여 첫번째 for문 순회 이후 5가 되어버린 i를 출력하게 되는 것이다.
이를 클로저를 사용하여 고쳐보자.
arr = []
for (var i = 0; i < 5; i++){
arr[i] = (function(id){
const free_variable = id;
return function(){
return free_variable
}
})(i);
}
for (var j = 0; j < arr.length; j++){
console.log( arr[j]() );
}
첫번째 순회 과정에서 IIFE(즉시실행함수표현)
을 사용하여 i를 인자로 전달하고, 이를 id
라는 이름으로 받아서 클로저가 참조할 수 있는 자유변수 free_variable
로 저장했다. free_variable을 참조하여 반환하는 함수 (클로저 라 하자) 를 실행하게 되면, 각기 다른 lexical environment를 참조하여 i 값을 free_variable에 저장해 두었기 때문에 해당 코드의 출력 결과는 처음 의도했던 대로 0,1,2,3,4 가 된다.
어렵지 않은 예제를 하나 더 살펴보자.
var count = 0
var counter = function(){
return count++
}
console.log(counter());
console.log(counter());
console.log(counter());
console.log(counter());
...
당연히도 전역변수 count를 참조하여 계속 늘어나는 count 값을 리턴할 것이다.
전역변수를 사용하면 추후 다른 코드에 의해 더럽혀지는(?) 불상사가 일어날 수 있기 때문에, 클로저를 사용하여 변수 counter를 숨겨주도록 해보자.
var counter = (function(){
var count = 0;
return function(){
return count++;
}
})();
console.log(counter());
console.log(counter());
console.log(counter());
...
쨔잔! 클로저를 사용해서 리팩토링 해 보았다.
끄-읕.
조금 더 복잡한 예제들은 아래 링크를 참조해보세요?