JavaScript

클로저

클로저

클로저(closure)는 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가르킨다. 클로저는 자바스크립트를 이용한 고난이도의 테크닉을 구사하는데 필수적인 개념으로 활용된다.  

내부함수

자바스크립트는 함수 안에서 또 다른 함수를 선언할 수 있다. 아래의 예제를 보자. 결과는 경고창에 coding everybody가 출력될 것이다.

function outter(){
    function inner(){
		var title = 'coding everybody';	
		alert(title);
	}
	inner();
}
outter();

위의 예제에서 함수 outter의 내부에는 함수 inner가 정의 되어 있다. 함수 inner를 내부 함수라고 한다.

내부함수는 외부함수의 지역변수에 접근할 수 있다. 아래의 예제를 보자. 결과는 coding everybody이다.

function outter(){
    var title = 'coding everybody';  
    function inner(){        
    	alert(title);
	}
	inner();
}
outter();

위의 예제는 내부함수 inner에서 title을 호출(4행)했을 때 외부함수인 outter의 지역변수에 접근할 수 있음을 보여준다.

클로저

클로저(closure)는 내부함수와 밀접한 관계를 가지고 있는 주제다. 내부함수는 외부함수의 지역변수에 접근 할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근 할 수 있다. 이러한 메커니즘을 클로저라고 한다. 아래 예제는 이전의 예제를 조금 변형한 것이다. 결과는 경고창으로 coding everybody를 출력할 것이다.

function outter(){
    var title = 'coding everybody';  
    return function(){        
    	alert(title);
	}
}
inner = outter();
inner();

예제의 실행순서를 주의깊게 살펴보자. 7행에서 함수 outter를 호출하고 있다. 그 결과가 변수 inner에 담긴다. 그 결과는 이름이 없는 함수다. 실행이 8행으로 넘어오면 outter 함수는 실행이 끝났기 때문에 이 함수의 지역변수는 소멸되는 것이 자연스럽다. 하지만 8행에서 함수 inner를 실행했을 때 coding everybody가 출력된 것은 외부함수의 지역변수 title이 소멸되지 않았다는 것을 의미한다. 클로저란 내부함수가 외부함수의 지역변수에 접근 할 수 있고, 외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 소멸되지 않는 특성을 의미한다.

조금 더 복잡한 아래 예제를 살펴보자. 아래 예제는 클로저를 이용해서 영화의 제목을 저장하고 있는 객체를 정의하고 있다. 실행결과는 Ghost in the shell -> Matrix -> 공각기동대 -> Matrix 이다.

function factory_movie(title){
    return {
        get_title : function (){
			return title;
		},
		set_title : function(_title){
			title = _title
		}
	}
}
ghost = factory_movie('Ghost in the shell');
matrix = factory_movie('Matrix');

alert(ghost.get_title());
alert(matrix.get_title());

ghost.set_title('공각기동대');

alert(ghost.get_title());
alert(matrix.get_title());

위의 예제를 통해서 알 수 있는 것들을 정리해보면 아래와 같다.

1. 클로저는 객체의 메소드에서도 사용할 수 있다. 위의 예제는 함수의 리턴값으로 객체를 반환하고 있다. 이 객체는 메소드 get_title과 set_title을 가지고 있다. 이 메소드들은 외부함수인 factory_movie의 인자값으로 전달된 지역변수 title을 사용하고 있다.

2. 동일한 외부함수 안에서 만들어진 내부함수나 메소드는 외부함수의 지역변수를 공유한다. 17행에서 실행된 set_title은 외부함수 factory_movie의 지역변수 title의 값을 '공각기동대'로 변경했다. 19행에서 ghost.get_title();의 값이 '공각기동대'인 것은 set_movie와 get_movie 함수가 title의 값을 공유하고 있다는 의미다.

3. 그런데 똑같은 외부함수 factory_movie를 공유하고 있는 ghost와 matrix의 get_title의 결과는 서로 각각 다르다. 그것은 외부함수가 실행될 때마다 새로운 지역변수를 포함하는 클로저가 생성되기 때문에 ghost와 matrix는 서로 완전히 독립된 객체가 된다.

4. factory_movie의 지역변수 title은 2행에서 정의된 객체의 메소드에서만 접근 할 수 있는 값이다. 이 말은 title의 값을 읽고 수정 할 수 있는 것은 factory_movie 메소드를 통해서 만들어진 객체 뿐이라는 의미다. JavaScript는 기본적으로 Private한 속성을 지원하지 않는데, 클로저의 이러한 특성을 이용해서 Private한 속성을 사용할 수 있게된다.

참고 Private 속성은 객체의 외부에서는 접근 할 수 없는 외부에 감춰진 속성이나 메소드를 의미한다. 이를 통해서 객체의 내부에서만 사용해야 하는 값이 노출됨으로서 생길 수 있는 오류를 줄일 수 있다. 자바와 같은 언어에서는 이러한 특성을 언어 문법 차원에서 지원하고 있다.

아래의 예제는 클로저와 관련해서 자주 언급되는 예제다. 

var arr = []
for(var i = 0; i < 5; i++){
	arr[i] = function(){
		return i;
	}
}
for(var index in arr) {
	console.log(arr[index]());
}

함수가 함수 외부의 컨텍스트에 접근할 수 있을 것으로 기대하겠지만 위의 결과는 아래와 같다.

5
5
5
5
5

위의 코드는 아래와 같이 변경해야 한다.

var arr = []
for(var i = 0; i < 5; i++){
	arr[i] = function(id) {
		return function(){
			return id;
		}
	}(i);
}
for(var index in arr) {
	console.log(arr[index]());
}

결과는 아래와 같다.

0
1
2
3
4

클로저 참고

댓글

댓글 본문
작성자
비밀번호
  1. 김명수
    정말 감사합니다!! 덕분에 클로져 이해됐어요
  2. 백수
    var a= outter(){
    return inner(){}};

    a()를 실행하면 a는 outter()에서 리턴받은 inner()를 가리키기 때문에 inner()가 실행
    그리고 inner()가 실행 되면서 outter()에 영향을 줌.

    전역변수를 사용하게 되면 다른 플러그인과 충돌 위험이 있기때문에 사용을 자제하는데
    이 closure라는 기술을 활용하면
    지역변수가 전역변수처럼 함수가 실행될때마다 변하는 private변수로 만들수 있음
  3. 완료!
    완료! 감사합니다 ㅠ
  4. 카구
    클로저를 열심히 이해한 학생입니다!!!
    이고잉님이 클로저를 위해서 설명해주신 두 가지 예제는 context라는 이해가 기반이 되어야 합니다.
    context란 말그대로 문맥을 의미합니다...

    var arr = []
    for(var i = 0; i < 5; i++){
    arr[i] = function(){
    return i;
    }
    }
    for(var index in arr) {
    console.log(arr[index]());
    }

    이 예제에서 for문 내의 function은 for문의 context, 문맥에 접근하지 못합니다!
    function들은 i를 리턴하는 함수일 뿐인거죠, 아직 호출이 된 상태가 아닌 것입니다.
    그래서 for(var index in arr)을 통해 로그를 출력하게 되면 함수들이 각각 호출되면서...
    for문의 context(문맥)이 끝난 시점의 i인 5를 출력하게 되는 것이랍니다!!!

    var arr = []
    for(var i = 0; i < 5; i++){
    arr[i] = function(id) {
    return function(){
    return id;
    }
    }(i);
    }
    for(var index in arr) {
    console.log(arr[index]());
    }

    하지만 이처럼 외부함수를 통한 내부함수의 context 접근 (== 클로져)를 사용하게 되면 아래의 for문을 통해 arr[]에 저장된 함수들을 호출하면서 index인 0, 1, 2, 3, 4... 를 던져주게 되는 거죠!! 즉 값을 출력하는 0, 1, 2, 3, 4는 위쪽의 for문의 i를 통해 전달되는 것이 아니라 아래의 for문을 통해서 전달되게 되는 거랍니다!!!
  5. 짱구파워
    감사합니다~
  6. SoGood
    설명 진짜 아름답습니다~
  7. whoever
    갈수록 별로네..
  8. refers
    자답입니다.. String가 위 강의에서 대문자 S가 아니고 소문자 s네요...
    대화보기
    • refers
      3번째 영상 맨 마지막에 if(typeof _title === 'String') 이부분에서 인자를 1로 보내도 false이고 '공각기동대'를 보내도 false값이 리턴되는데 저만 그런건가요? ㅜㅠ
      입력하신 값은 문자열이 아닙니다를 출력하려는데 둘다 false라 문자열을 입력해도 같은 메시지입니다.
    • 이현섭
      함수를 IIFE로 만드셧네요. 틀린 건 아닙니다. 하지만 클로저라는 맥락에서 볼때는 정답이 아니긴해요. 클로저를 통해 환경을 새로 만드는 것이 핵심이지 함수자체를 즉시 실행시키는다는 점이 핵심은 아니니까요..

      이런 코드는 어떨까요?

      var i;
      for(i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, i * 100);
      }

      i를 0.1초마다 출력하는 예제입니다. 여기선 의도대로 0, 1, 2, 3, 4가 차례로 출력되지 않고 5가 5회 출력되겠죠.
      여기서 IIFE를 사용하면 어떻게 될까요?

      var i;
      for(i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }(), i * 100);
      }

      0, 1, 2, 3, 4가 순서대로 출력되긴 합니다. 그런데 원래 의도대로 0.1초마다 출력되지 않고 한번에 출력되죠. 함수 내부의 실행구문이 즉시 실행되기 때문이에요. 여기서는 제대로 동작시키려면 클로저를 만드는 수 밖에 없습니다.

      var i;
      for(i = 0; i < 5; i++) {
      (function(j) {
      setTimeout(function() { console.log(j); }, j * 100);
      })(i);
      }

      의도가 이해되시나요?
      대화보기
      • 학생입니다
        arr=[];
        for(var i=0 ; i<5 ; i++){
        arr[i]=function(id){
        return id;
        }(i)
        }

        for(var index in arr){
        console.log(arr[index]);
        }

        이렇게해도 0/1/2/3/4 나오네요 . (당연한거겠찌만.. ㅠ)
        이해를 돕기위한 예제라는 건 알지만
        혹시나 해서 질문드려요.

        마지막 예문에서 내부함수를 굳이 만들 이유가 있나요 ?
        테클아닙니다 오해마십시오
      • 학생입니다
        황주현님 짱!! function a(){}() 중괄호 뒤에 소괄호가 또 오는 걸 처음봐서 너무 헷갈렸는데 ㅠㅠ 고맙습니다~
      • 김은희
        자바스크립트만의 독특함이 함수에 있는 걸까? ^^;; 피상적으로는 이해하겠는데, 구체적으로 와닿지 않습니다. 역시 반복학습이 필요하겠지요~
      • ibmike
        언어는 원래 다 어렵습니다 ㅎㅎ
        대화보기
        • yihsang
          이고잉님 감사드립니다.
        • oddshin
          며칠 간격을 두고 세번 보니 이해가 조금씩 되는거 같아요 ^^
        • 지영
          누가 자바스크립트 쉽다 그랬어
        • astron
          헷갈리고 막막했었는데 덕분에 한방에 이해가 갔습니다 감사합니다 ^^
          대화보기
          • 다배울거야
            priavate 변수로 선언하는 부분 말인데요, 자바에서는 그냥 private String title; 이라고 선언하면 되는 것을 자바스크립트에서는 자바같은 저런 방법이 없어서 힘들게 하는건가요??
          • ziggystory
            알듯 말듯 .. 참 난감하네요... 빨리 한번 보고 다시 정주행 해야 할 것 같네요 ㅠ
          • fasdgoc
            내부함수는 외부함수의 지역변수에 접근할 수 있다.
          • 이주환
            2016. 04. 24

            항상 공부하면서 클로저를 보지만

            처음에 보면 정말 난해하게 생각될수있지만 자주보고 사용하다보면 언뜻 이해하게 되는 날이 옵니다.
          • JustStudy
            고맙습니다.
          • serpiko.tistory.com
            [기본- 원리 - 응용 예제를 덧붙입니다]


            클로저는 독립적으로 클로저 안에 정의된 함수를 기억하기 위해서 사용합니다.

            주의할점은 클로저가 필요하지 않은 작업인데도 함수안에 함수를 만듬으로써

            스크립트 처리 속도와 메모리 사용량 모두에 부담을 주므로 유의하여야 합니다.

            실용적인 클로저란

            "하나의 객체에서 여러가지 이벤트에 반응하는 콜백(위의 첫번째 예제처럼)을 사용하는 상황" 에 매우 적합하다.

            일단 지역변수를 Private로 사용하기 위해서

            function(){}(); 보다

            (function(){})(); <- 직관성이 좋으므로 이 함수의 사용법을 권장합니다.




            //값으로 출력
            var arr = [];

            for(var i = 0; i < 5; i++){

            arr[i] = (function(id) {

            return id;

            })(i);
            }


            for(var index in arr) {
            console.log( arr[index] );
            }


            결과 0 1 2 3 4

            실행되는 원리를 알기위해 함수대신 값으로 찍어봅시다.

            arr[index] 는 현재 리턴되는 자기 자신







            //arr[index] 실행 주체의 개념을 알기위해서 : 클로저 내부의 객체의 이름으로 출력
            var arr = [];

            for(var i = 0; i < 5; i++){

            arr[i] = (function(id) {

            return{
            getValue : function(){
            return id;
            }
            }
            })(i);
            }


            for(var index in arr) {
            console.log( arr[index].getValue() );
            }


            결과 0 1 2 3 4

            arr[index]에서 자신을 객체형으로 만들고 멤버변수로 getValue를 참조하여 값에 접근






            //만약에 실무에서 재활용이 가능한 클로저를 제가 쓴다면
            var arr = [];
            for(var i = 0; i < 5; i++){

            arr[i] = (function(id) {

            var obj = {
            getValue : function(){
            return id;
            }
            }
            return obj;

            })(i);
            }


            for(var index in arr) {
            console.log( arr[index].getValue() );
            }


            결과 0 1 2 3 4

            실무에서는 제가 사용했던

            예제 1: 값만 출력,

            예제 2 : 이름이 없는 오브젝트로 사용하는게 아니라

            마지막 예제 3번 처럼

            객체를 명시적으로 선언하고 이 객체를 사용하여

            Extend 혹은 Chainning 기법(객체가 jquery 객체일경우..) 으로 사용됩니다.
          • ㅇㅇㅎ
            진짜 도움이 많이 되는 댓글이었습니다.
            감사합니다!
            대화보기
            • 초보웹 개발자
              클로져가 어렵기는 어려운가 보네요.
              질문에 코드가 많이 올라와 있는것을 보니...
              정말 열심히하는 학생들이 많네요.....
              열성이 부럽습니다.
            • var arr = []
              for(var i = 0; i < 5; i++){
              arr[i] = function(){
              return i;
              }
              }

              for(var index in arr) {
              console.log(arr[index]());
              }

              > arr[3]();
              5 // i = 5 이기 때문에 5가 리턴됨

              > for(var i = 0; i < 5; i++){ console.log(arr[i]()); }
              0
              1
              2
              3
              4
              // 여기서 이렇게 실행 되는 이유를 물으 셨는데, 다음에 계속 이어지는 몇번의 실행 예제를 보시면 이해가 가실 것 같습니다.

              > i = 3;
              undefined
              > arr[1]();
              3

              // 보시면 아시겠지만 for 문 안에 var i = 0 문이 실행되면서 이미 배열안에 저장되있는 익명 함수가 참조하고 있는 전역 변수 i 가 변경 되었고, for 문이 돌면서 전역변수 i는 계속 변경되기 때문에 0, 1, 2, 3, 4 라고 나오게 되는 것입니다.
              대화보기
              • 티거리스
                마지막 예제 이해가 잘 안되서 연습해본 소스입니다
                var arr = []
                for(var i = 0; i<5; i++){
                arr[i] = function(){
                return i;
                }
                document.write(arr[i]+"<br />");
                }

                이렇게 한다면
                arr[0] = function(){return i;}
                arr[1] = function(){return i;}
                .
                ....이 된다는 것은 이해했습니다.

                따라서
                for(var index in arr){
                document.write(arr[index]());
                }
                를 출력하면 5 5 5 5 5 가 출력된다는 것도 이해가 됐습니다
                최종적인 전역변수 i는 현재 5를 가지고 있기때문이죠

                연습해본 소스의 첫번쨰는

                document.write(arr[0]());
                document.write(arr[1]());
                document.write(arr[2]());
                document.write(arr[3]());
                document.write(arr[4]());

                입니다.
                이렇게 출력을 해봐도 역시 55555를 출력합니다
                arr[0],arr[1]... 가 각각 function(){return i;} 를 출력하기 떄문이죠..

                그런데 마지막 연습한

                for(var i = 0; i<5; i++){
                document.write(arr[i]()+" ");
                }

                위의 소스는 0 1 2 3 4 를 출력합니다
                제가 예상한 값은 55555 인데요

                왜 이렇게 되는 것인지 이해가 잘 안됩니다 ㅠㅠ
                위의 소스와 그 바로위의 소스가 같다고 생각하는데.. 혹시 왜이렇게 되는지 아시는분 답글부탁드립니다!

                밑의 소스는 제가 연습한 전체 소스입니다.
                ------------------------------------------------------------------------------------------------
                <!DOCTYPE html>
                <html lang="en">
                <head>
                <meta charset="UTF-8">
                <title>Closure_Demo2</title>
                </head>
                <body>
                <script>

                var arr = []
                for(var i = 0; i<5; i++){
                arr[i] = function(){
                return i;
                }
                document.write(arr[i]+"<br />");
                }
                document.write("<br />");

                for(var i = 0; i<5; i++){
                document.write(arr[i]()+" ");
                }
                document.write("<br />");
                document.write(arr[0]());
                document.write(arr[1]());
                document.write(arr[2]());
                document.write(arr[3]());
                document.write(arr[4]());
                document.write("<br />");

                for(var index in arr){
                document.write(arr[index]());
                }


                </script>
                </body>
                </html>
              • Byeong Koo Kang
                아랫 글들을 살펴봤는데 핵심은 즉시 실행의 문제였군요.
              • tinybit
                안녕하세요. 3번째 영상에 대해서 저도 많이 부족하지만 조금이라도 도움이 될까싶어서 글을 남깁니다..

                엔트님이 헷갈리시는게 2개가 있는것같은데..
                1. 변수에 함수를 넣은후 함수를 호출할때 이미 타이틀이 변수로 치환이 되어있는건지. 아니면 호출될때 죽어있던곳에서 값을 가지고 오는지?
                2. 외부함수를 호출할때마다 같은 함수가 반복으로 호출이 되는가? 독립적인 함수가 호출되는가?가 맞는가요?

                1의 경우 ghost = factory_movie('Ghost in the shell');로 ghost에 객체를 넣었을때 클로저의 정보가 함께 저장됩니다. 클로저의 정보에 내부변수로 타이틀도 가지고 있어요. ghost 를 console.log 해보시면 get_title, set_title 그리고 그외 여러정보를 가지고있는데 (proto같은..) 찾아보시면 closure가 있고 그 안에 타이틀이 있어요.
                그러므로 정확한 표현은 접근가능한 클로저정보로서 내부변수를 가지고있다. 가 되겠네요.

                2는 독립적인 함수가 호출됩니다. 같은 factory_movie함수를 써서 만들었지만 factory_movie함수는 틀일 뿐이고 만들때 지정한 타이틀로 새로운 객체를 생성해서 각각의 변수에 넣은겁니다. 전에 넣은 변수가 남아있다던지 객체가 남아있다던지는 하지않아요.
                대화보기
                • Cho Jeaho
                  계속 보기는 하는데... 점점 어려워지고 있어요..ㅜㅜ 중간중간 이해가 안가더라도 이고잉님이 말씀하신대로 우선 넘어갈게요... 원래 성격으로는 이해안가는거 못넘어가는 성격인데... 시간이 많이 없어서..ㅜㅜ
                • 으 어렵네요..ㅜ
                • 일단 패스.
                • 질문을 제대로 이해했는진 잘 모르겠습니다만,

                  제가 이해한 바로는,

                  ghost = factory_movie('Ghost in the shell');
                  matrix = factory_movie('Matrix');
                  을 실행한다면 ghost 와 matrix 안에는 완전히 독립된 객체로 저장됩니다.
                  외부함수가 실행될 때마다 새로운 지역변수를 포함하는 클로저가 생성됩니다.
                  //참고 위에 3번을 읽어보시면 나옵니다.

                  ghost 안에는 title변수가 'Ghost in the shell' 인 객체가,
                  matrix 안에는 title변수가 'Matrix'인 객체가 저장되어 있는 것이죠.
                  그래서 똑같은 외부함수를 공유하고 있어도 결과는 다르게 나옵니다
                  또, 각 title을 접근할 때는 매소드(get_title, set_title)를 통해서만 접근을 할 수 있고요(private variable)

                  요약부분에 전자가 맞다고 생각이 드네요

                  제가 이해한 대로 답변을 해보았습니다.
                  혹시 틀리면 꼭 지적해주세요!
                • SK Kim
                  Closure 부분 다시 확인해야 할듯..ㅠㅠ
                • WayneKing
                  아주 재미있는 부분이네요.
                  옆차기가 날리고 싶지만 웹환경에서는 어쩔 수 없는 핸디캡인듯하네요.

                  아니면 댓글 좀 ㅠㅠ
                  이벤트기반이라~ 그런 거 맞죠?!
                • 엔트
                  4번쨰 강의 보고 이해한게 맞나 댓글남겨봅니다 어려운 내용인거같아 확실하게 알고 넘어가고자합니다
                  제가 이해한게 틀리다면 어디부분이 틀린지 댓글남겨주시면 공부하는데 큰도움이 될듯합니다 !!

                  첫번쨰 예문은 5가 5번출력되는데 그이유는 for문이 돌면서 arr[i]변수안에 함수를 저장합니다
                  이떄 functin(){return i; } 이걸 arr[0] = functin(){return i; } ,arr[1] = functin(){return i; } ,arr[2] = functin(){return i; } ~arr[4] = functin(){return i; } 이런식으로 다섯번 저장합니다 하지만 이떄 함수안에 있는 i라는 리턴값은 외부에 있는 변수인 i값이 계속 변하기떄문에 함수안에있는 i값또한 계속 변하게되고
                  for문이 끝나는 i(예:5)<5가 되었을떄 i는 5가되고 함수안에 있는 i 값또한 5가되어 arr라는 변수안에있는 모든 i값이
                  5가 됩니다

                  여기까지 첫번쨰 5가 출력되는 이유이고 이걸 방지하기 위해서는 i를 가져와서
                  내부 함수의 i을 바꾸되 외부의 i는 계속 변하기때문에 값은 주되 한번준 값이 확정되게 할수있는 방법이 바로 두번째 인거 같습니다
                  그러기위해서는 내부함수가 가져올수잇는 외부함수를 만들고 그 인자의
                  값을 i라는 변수? 값이 아닌 다른 값(분문처럼 id, 다른 이름도 상관없음)을 준후 함수실행명령안에 인자값을 변수 i로 바꾼다면
                  함수 실행 값은 i에 따라 변하면서 함수 실행명령을할떄 i라는 변수의 인자를 외부함수 id에 대입하게되고 한번 지정된 이값은 더이상 바뀌지 않기떄문에 외부함수 인자가 0 ,1,2,3,4 로 순차적으로 확정되고 이값은 내부함수의 id 가 가져와서 리턴하게됩니다 i는 계속 바뀌지만 id의 값은 함수실행명령인 (i) 이걸로인해 한번만 실행되고 바뀌기 떄문에 더이상 가변적이 아닌 고정적인 값이?된다고 저혼자 상상의 나래를 펼쳤습니다 ;
                  . 지식이 부족하여 설명이나 제대로 했나 모르겟네요 ㅠㅠ 중간중간 용어부분중에 틀린게 있을듯합니다 글 흐름에 맞게 번역?하시면 됩니다 ㅠㅠ 제가 이해력이 딸려서 몇시간동안 생각해서 이정도 결론밖에 내리지못하였습니다 많은 채찍?질부탁드립니다!!
                • 엔트
                  꼭 알고싶어서 회원가입까지 했습니다!

                  3번째 강의 보다가 의문점이생겨서 질문 올립니다
                  function factory_movie(title){
                  return {
                  get_title : function (){
                  return title;
                  },
                  set_title : function(_title){
                  title = _title
                  }
                  }
                  }
                  ghost = factory_movie('Ghost in the shell');
                  matrix = factory_movie('Matrix');

                  document.write(ghost.get_title());

                  이부분에서 factory_movie('Ghost in the shell'); 함수를 호출?하면
                  'Ghost in the shell'을 외부함수의 인자로 전달? 된다고 알고있는데
                  그렇다면 외부함수의 리턴값을 ghost = {
                  get_title : function (){
                  return title;
                  },
                  set_title : function(_title){
                  title = _title
                  }
                  } 이런식으로 고스트라는 변수에 저장?될때 get_title 메쏘드?함수?의 title이 'Ghost in the shell' 이걸로 치환되있는건지 아니면 밑에서 alert(ghost.get_title()); 요 메소드?를 실행시켰을때 죽어있던 외부함수의 인자값을 가지고 와서 출력하는건지요? 아는게 미천한지라 질문하기도 힘드네요 ㅠ
                  이런 의문점을 가지는 이유는 만약 ghost.get_title 요 메소드를 실행시키기 전까지 외부함수에만 'Ghost in the shell' 이라는 인자가 포함되어있다면
                  factory_movie('Ghost in the shell'); 이걸 호출하고 바로
                  factory_movie('Matrix'); 이 호출을 실행시켰을떄
                  기존에 외부함수에 있던 'Ghost in the shell'라는 인자가 'Matrix'이걸로 치환?되고 alert(ghost.get_title()) 요걸 실행시켰을때 title값으로 'Matrix' 가져오지않을까 하는 의문점이생겼습니다 .
                  아니면 함수를 호출할떄마다
                  function factory_movie('Ghost in the shell') ,function factory_movie('Matrix')
                  이런식으로 독립적으로 외부함수가 만들어져서 나중에 (ghost.get_title() 메쏘드?를 실행시켰을때 각각의
                  외부함수에서 인자를 가져오는건지 궁금합니다 . 지식이 전무한상태에서 질문할려니 힘드네요 ㅠㅠ
                  아는 만큼 보인다 라는말이 절실하게 와 닿습니다

                  요약하자면 함수를 호출할때 외부함수에 인자를 넣고 리턴값으로 내부함수를 변수에 넣을떄 이 내부함수에잇는 title 요놈이 'Ghost in the shell' 요걸로 변경되있는건지 아니라고 한다면
                  예문에서처럼 ghost = factory_movie('Ghost in the shell');
                  matrix = factory_movie('Matrix'); 이런식으로 연달아 사용했을떄 두번쨰 함수를 실행시켜면 기존에잇던
                  외부함수의 인자값('Ghost in the shell')이놈이 ('Matrix') 요놈으로 바껴서
                  그다음 실행하는 alert(ghost.get_title());요걸했을때 외부함수의 마지막 인자값인 ('Matrix') 를 가져와서
                  화면에 뿌려줘야한다고 생각이 들어서..아 설명하기 힘드네요 용어들이 생소해서 어떤식으로 설명할지가 참....
                • 고고
                  지역변수나 전역변수는 함수안에서만 유효하다고해서 아 그런가보다 했더니 내부함수를 사용해서 함수 바깥에서도 사용하게 만들어놨군용
                • 자스입문
                  C계열만 사용했던 저로써는 당황스러운 기능이네요... 마지막 예제는 그런것을 이용한 트릭을 이용하는것을 보여준듯 하구요

                  for문 괄호 안에 선언된 i가 안죽고 계속 최후의 값 5를 담고있는 상태로 살아있으니 이거 적응할려면 좀 힘들겠는데요 ㅠㅠ i값은 5로 최종적으로 정해지다보니 arr안의 함수는i를 리턴하는데 i는 5니까 죄다 5가 찍히는 거같은데..
                  for (var i = 0; i < 5; i++)
                  {
                  }
                  alert(i);
                  자스는
                  이러면 5가 메시지박스에 찍히더군요 원래는 i가 어딧노? 이러면서 에러떠야되는데 ㅋㅋㅋ C계열 하신분들은 좀 당황스러우실것 같습니다
                  일단은 함수 외부의 '지역변수'에 접근 가능 이렇게 이해만 하고 넘어가도좋을듯 하네요
                • 햌커
                  그러게요 외부함수가 죽을때 내부함수에게 변수 물려주고 죽네요
                  이거 잘 이용하면 보안 뚫을때도 좋을듯한 예감이 드네요 웬지모르겠지만 ㅋㅋ
                  대화보기
                  • 자바8쪽 람다식이랑 클로저 보다가 생각나서..
                    자바스크립트 클로저라는게 궁금해서 보는데 ...
                    오.. 신기하네요..
                    자기호출 함수 보니 람다랑 비슷해보이고..

                    접근시 자바는 final 로 닫히는데.. 자바스크립트는 변경 가능한가보네요.. +_+
                    오홍 신기함 .. 생각이 늘어나는 느낌...
                  • 클로저클나저
                    3일째 머물러 있는데...클로저 마지막 강의는 아직도 어렵네요...
                  • bluetree
                    저의 이해가 맞는지는 모르겠지만,

                    "외부함수에 의해 리턴된 내부함수를 변수로 사용하는 경우,
                    내부함수가 만들어졌을 때의 외부함수의 변수 값도 함께 가지고 있다"라고 이해되네요.
                  • sharu
                    감사합니다.. 마지막문제 이해가 잘안되지만.. 패스!
                  • derrick
                    덕분에 이해되는데 도움됬습니다. 감사합니다.
                    대화보기
                    • 황주현
                      클로저에 대해서 설명 감사합니다. 마지막 예문은 설명이 없으셔서 제가 조금만 덧 붙이겠습니다.

                      쉽게 생각해서 클로저는 이름 그대로 닫혀버린 녀석(?) 이라고 생각하시면 됩니다.

                      함수 안의 내부함수나 그 로컬 변수들은 그 외부함수의 밖에서 접근을 못하죠.

                      즉, 내부함수와 로컬변수들은 외부에서 접근되지 못하게 외부 함수에 의해서 닫혀버린 겁니다. 클로저! (닫혀버린 녀석들)

                      그런데 재밌는건, 다른 언어와 차이나는, 자바스크립트는 특성상 상위 scope (함수 외부)에서 선언된 변수 (함수 선언전에 선언된 변수)가 함수 내부에서도 사용될 수 있습니다.

                      뭐? 뭐시라? 뭔 말이여? 쉽게 말하면 위에서 선언된 변수가 밑에 선언된 함수 안에서도 사용될 수 있습니다. C++, Java 등 다른 언어에서는 있을 수 없는 일이죠.

                      그럼 이런 자바스크립트의 scope 특성과 함수 안에 선언된 함수로 무엇을 할 수 있을까요?

                      자바 스크립트 함수에 OOP처럼 private 멤버를 만들 수 있습니다.

                      외부함수 내에 로컬 변수를 선언하고 그 밑에 내부함수를 정의하는 거죠.

                      그럼 내부 함수에서 외부함수의 로컬 변수들을 사용할 수 있겠죠? 또한 외부함수의 밖에서 정의된 변수에도 접근할 수 있습니다.

                      내부 함수와 로컬 변수들이 private 멤버가 되는거구요. public 멤버를 위해서 내부 함수나 내부함수를 가리키는 객체를 리턴하는 겁니다.

                      (위의 factory_movie 참조)

                      이제 마지막 예문 설명입니다. 마지막 예문의 첫번째는 arr[i] = function() { return i; }를 하고 있죠?

                      arr[i] 에 함수를 저장하는 겁니다. 그리고 그 함수는 외부 변수인 i를 리턴하죠.

                      첫번째 for 문이 끝나고 console.log(arr[index]())를 하기 직전 i의 값은 얼마일까요?

                      네~ 첫번째 루프에서 0~4까지 할당되고 마지막에 i++이 되었으니 답은 5 입니다.

                      arr[index]는 외부 변수 i를 리턴하게 되어있죠? 그래서 5 5 5 5 5 가 찍히는 겁니다.

                      두번째 예문은 좀 복잡하죠? arr[i]에 외부 함수의 호출값을 저장합니다. 함수 자체가 아닙니다. 호출값입니다.

                      즉, 호출값은? 내부 함수인 클로저 입니다. 그 클로저는 id를 리턴하죠. i 가 아닙니다.

                      arr[i] = function(id) { return function() { return id; } }(i);

                      끝에 (i) 보이시죠? 저 i의 값이 id로 할당이 되고 내부 함수에서는 할당된 id가 리턴 됩니다.

                      for 문을 돌면서 i는 0~4까지 이니 id의 값은 0~4가 할당이 되구요. 내부함수에서는 그 id 값인 0~4를 각각 리턴합니다.

                      그래서 결과는 0 1 2 3 4

                      그런데 이 문장이 좀 헷갈리시죠?

                      arr[i] = function(id) { return function() { return id; } }(i);

                      이건 자바스크립트의 IIFE (Immediately Invoked Function Expression) 패턴입니다.

                      IIFE는 또 뭐야? ㅡ.ㅡ;; 하시는 분이 계시겠지만 여기선 짧게만 설명드릴께요.

                      위의 문장을 다시 적으면 이렇게 적을수 있구요. (동일 합니다. 괄호만 추가)

                      arr[i] = (function(id) { return function() { return id; } })(i);

                      보기 좋게 짧게 적으면

                      arr[i] = ( ... )(i); 입니다. arr[i]에 인자로 i를 넘겨서 함수를 호출한 값을 저장하는 겁니다.

                      저렇게 하면 i는 function(id) 의 id 값으로 들어가구요. 리턴된 값은 id 값을 리턴하는 내부함수가 되는겁니다.

                      id 는 0~4까지 할당 되었고 i가 5로 되더라도 변하지 않죠? 그래서 0 1 2 3 4라는 원하는 결과가 나오는 겁니다.

                      아... 주절주절 설명이 길어졌네요. 이제 일해야 겠습니다. 다들 즐프 하세요.
                    • 이경호
                      closure는 javascript가 private한 변수를 사용할 수 있도록 하는 좋은 메카니즘이다!
                      마지막 예제는 이해가 잘 안되네요. 좀 더 내공을 쌓고 나중에 다시와서 봐야겠습니다.
                      일단은 개념만 정리하고 갑니다!
                    • 베리스트롱
                      질문이 생겼습니다 ^ ^
                      재가 앞에 강좌들에서 어떤 부분을 놓친건지 잘 모르겠어서요
                      3/4 강좌 7:28
                      에 내용을 말씀해주시는 부분에서요

                      함수를 정의 할때
                      function 함수명( [인자...[,인자]] )
                      인것으로 알고 있었습니다

                      헌데 예제를 보면
                      function factory_movie(title)
                      에서 title이 factory_movie의 지역 변수라고 설명을 해주시고 있어서요

                      title은 인자가 아니라 지역 변수 인건가요?
                      아니면 인자는 지역 변수와 같은 말인간가요?

                      항상 좋은 강의 잘 듣고 있습니다 ㅎ
                    • 삽질중
                      for(var i = 0; i < 5; i++){
                      arr[i] = function(id) {
                      return function(){
                      return id;
                      }
                      }(i);
                      }
                      즉 arr[i] 에는 즉시실행함수가 실행되면서 return 되는 function(){ return id } 가 들어가게 되내요
                      즉시샐행들이 되면서
                      arr[0]=fucntion(){return 0};
                      arr[1]=fucntion(){return 1};
                      arr[2]=fucntion(){return 2};
                      .
                      .
                      이런식으로 들어가게 되는군여..
                      결국 for문 돌던 시점의 i 값을 결국 계속 지니게 되는...
                    버전 관리
                    egoing
                    현재 버전
                    선택 버전
                    graphittie 자세히 보기