클로저, 코드로 살펴보기

이동규 (Justin)·2020년 7월 31일
1

자 먼저 가장 흔한 예제로 시작해보자..


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());
...

쨔잔! 클로저를 사용해서 리팩토링 해 보았다.

끄-읕.

조금 더 복잡한 예제들은 아래 링크를 참조해보세요?


출처 - https://poiemaweb.com/js-closure

profile
Frontend Developer, JamStack, Ethereum

0개의 댓글