자바스크립트의 클로저(Closure)를 이해하고 이를 활용해 setTimeout() 함수에서 일어날 수 있는 일을 예측, 발생가능한 이슈를 수정하는 방법에 대하여 알아보려합니다.



# 자바스크립트의 클로저(Closure) 알아보기
클로저를 이해하기 위해서 하나의 예제를 만들어보려고합니다. 그 중에서 setTimeout()을 사용한 예제가 많이 사용되죠 ~ 그럼 아래코드를 통해 알아보겠습니다. 아래는 test 함수를 실행할 경우 1, 2, 3초에 0, 1, 2 문자를 콘솔창에 각각 출력하게 하는 코드입니다.
test = function () {
  for (i=0; i < 3; i++) {
    setTimeout(function() {
      console.log(i);
    }, 1000*i);
  }
}

함수를 실행하면 0, 1, 2가 나타날까요? 실제로 구현해보면 원했던 결과가 나타나지 않습니다... 출력되는 결과는 아래와 같이 각각 2, 2, 2이 출력됩니다.
2
2
2

왜 0, 1, 2의 값이 나타나지 않을까요? 그 이유는 무엇일까요? 네. 그 이유가 바로 클로저입니다. 클로저에 대하여 이해가 필요합니다. 클로저가 무엇인지 조금은 이해하고 있다는 전제하에 아래에 설명해 보겠습니다.


! 위 예제에서 나타난 클로저의 설명
이해하기 어려울 수 있지만 가장 간단하게 설명하자면 setTimeout()함수의 내부에는 또 다른 익명함수가 있으며 이 익명함수에서 저장된 변수의 값이 다르게 저장되어 있기 때문입니다. 이 결과가 출력되므로 다른 값이 나타나게되는 것이죠... 왜 변수에 저장된 값이 다르냐는 바로 클로저가 하는 일 때문입니다. 클로저가 내부 함수에서 외부 함수의 변수에 접근한다는 것을 아시고 계시죠? 이 때 내부 함수에서 저장한 외부 함수의 변수는 독립된 공간을(Scope) 만들어 변수를 저장하게되는데 다시 변수가 호출 되는 경우 가져온 값은 참조 값 형태가됩니다.


! 예제에서 클로저 찾기
일단 아까의 예제에서 클로저를 찾아보죠. for문 내부의 setTimeout() 구문을 살펴보세요.
setTimeout(function() {
  console.log(i);
}, 1000 * i);

setTimeout() 내부에 있는 함수가 보이시죠? 이는 익명함수인데 i의 값을 불러와 출력하는 구조입니다. 이때 i의 변수 선언이 없고 외부의 for문에서 가져오므로 i가 바로 클로저(Closure)입니다. for 문은 미리 실행되어 이미 2의 값을 가지고 있기 때문에 참조값을 가지는 클로저는 0,1,2가 아닌 2,2,2가 출력되는 것입니다.

위 내용을 다시 정리하면...
for문의 루프는 미리 실행되고 setTimeout()의 내부함수인 익명함수는 외부함수의 변수 i값을 가져와 함수를 실행하게된는데 미리 실행된 for문 때문에 변수 i의 값이 바뀌게 되고 바뀐 값이 클로저에 저장되어 setTimeout() 함수에 영향을 미치게 된것입니다. 클로저가 만들어지게되면? 이때 클로저는 임시객체를 만들어 해당 스코프내의 모든 데이터를 저장하게 되고... 여기에 외부함수의 변수도 저장되게됩니다. 이 내장객체는 함수가 닫치는 경우 사라지게 됩니다.



# setTimeout()의 클로저를 우회하는 방법
그렇다면 setTimeout()을 사용할 때 클로저를 우회하는 방법을 알아봅니다. 즉 0,1,2가 출력되려면?? 그 해결 방법 중 한가지로 setTimeout() 함수에 들어갈 인자를 익명함수의 자기호출함수를 사용해 미리 다른 매개변수값으로 보내는 방법이 있습니다. 아래 예제를 봐주세요.
test = function () {
  for (i=0; i < 3; i++) {
    (function(x) {
      setTimeout(function() {
        console.log(x);
      }, 1000*x);
    })(i);
  }
}

출력된 결과를 확인하면 아래처럼 0, 1, 2가 콘솔창에 출력됩니다. 바로 원하던 결과입니다. 핵심은 for 루프문에서 사용된 변수값 i를 직접 참조할 경우 클로저가 발생하므로 익명함수의 매개변수로 사용, 이를 이 함수의 인수로 받아 사용한다는 점입니다.