2015년 2월 24일 화요일

[난해한 Javascript 개념] closure의 개념

C/C++/Java에 익숙한 나에게 낯선 것들이 Javascript에는 너무나 많다. 지금까지 다루어 본 언어들과는 너무나 다른 functional 프로그래밍 언어인 Javascript의 핵심 요소를 살펴보고 '내 나름대로의 이해'를 시도해 본다.

낯선 것들:
  • first-class function


  • 변수의 scope


  • this 키워드의 의미


  • closure의 개념


  • Asynchronous Loop








  • closure
    개인적으로 Closure는 상당히 이해하기 어려운 개념인데, 나름 이해한 것은 timer 예제를 통해서이다. 개념적인 부분은 아직 모르는 부분이 많다는 것을 명심하고 나의 방식으로 한번 이해를 해보자.

    일반적은 for loop은 아래와 같다.

    위 코드의 출력은 다음과 같다.
    출력: 1, 2, 3, 4, 5, end


    그리고 조금 복잡해 보이는 아래 코드를 보자

    함수를 선언하고 즉시 실행했기에 위 코드의 출력도 동일하다.
    출력: 1, 2, 3, 4, 5, end


    1, 2, 3, 4, 5초 Timer를 실행시킨 아래의 코드를 보자.

    출력: end, 6, 6, 6, 6, 6 (end는 즉시, 6은 1초 간격으로 출력)

    function()이 실행되는 시점에는 이미 loop은 끝난 뒤로 setTimeout의 callback함수가 실행되는 환경은 for loop이 실행되는 환경과 다르게 된다.
    이때 callback함수내에서 선언되지 않은 변수 i는 외부에 선언된 i의 reference를 가지게 되어, callback이 실행되는 시점의 i값을 읽어오게 된다.
    loop이 종료된 시점이므로 i의 값은 6이 되는 것이다.

    callback을 시스템에 등록하는 시점과 실행되는 시점의 차이로 인해 의도하지 않은 결과가 나타나는 것이다.
    이것을 해결하기 위해서는 callback을 등록하는 시점의 변수값을 실행 시점에서 그대로 읽을 수 있도록, callback 등록 시에 변수 값을 저장하면 된다. 그것이 closure이다.


    출력: end, 1, 2, 3, 4, 5

    위의 코드는 기존의 callback(inner)을 다른 함수(outer)가 감싼 것처럼 보이는 형태이다. 이것을 해석해보자.
    function(x){}(함수 선언 형태)가 아니라 (function(x){})(i)(함수 실행 형태 = 함수 object + (argument))이므로 즉시 실행되는 (immedidate anonymous) function이다. 그리고 그 함수의 argument로 i가 passing된다.
    그런데, outer function이 즉시 실행이 되면, inner function(원래의 callback)의 object가 return되어 setTimeout의 callback으로 등록되는 것이다. 실행 시점의 inner function object내의 변수가 참조하는 값을 저장하기 위해, inner function과 쌍으로 존재하는 outer function을 정의하고, 참조할 값을 그 내부 변수(또는 argument)에 할당하는 것이다.


    위의 개념으로 아래 코드를 분석해 보면 더욱 이해가 용이할 것이다.






    정리
    1. Closure의 필요성: callback을 시스템에 등록하는 시점과 실행되는 시점의 차이로 인해 참조할 변수값이 변해 버릴 수 있다.
    2. Closure의 형태: 함수 object를 return하는 immediate anonymous 형태의 outer function을 만들고, 사용할 변수를 outer function에서 argument로 passing하라.






    댓글 없음: