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_title와 get_title 함수가 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. 금도끼은도끼
    클로저는 아주 중요한 개념입니다... 클로저를 어디다쓸가요??

    이런함수특성때문에 이전값을 기억해야하는경우
    예를 들어서 전자시계 00: 00:00 시계에서 시간을 기억했다가 시 분 초가 올라가는것
    그리고 게임에서 카운트가 올라가는경우등 많이 쓰이죠...

    참좋은 예제입니다..클로저는 함수에서 기존값을 잊지않고 기억하기위해서 만들어진 개념이죠..
    대화보기
    • 앙냥냥
      친절한 설명 감사합니다 ~ ^ㅇ^ 아직 100% 이해했다고 할 수는 없지만 덕분에 어려웠던 부분은 해결했어요!!
      대화보기
      • 금도끼은도끼
        함수는 함수내부에 변수(지역변수)가있으면 그걸사용하구
        없다면 외부에서 가장 최근 값을 사용합니다(이전 변수 값은 어디에도 저장되지 않습니다.)

        즉 arr[ i ] 의 i값과 function() { return i} 에서의 i값은 다른곳을 가르키고있는것이죠...

        함수특징인데 함수에서 i값은 먼저 함수내부에 i가있나 확인하구 있으면 그걸쓰고
        없으면 외부에서 찾는데 최종i값을 가져오게 되는겁니다..
        예를 들면 for문밖에다가 i =10;이라고 추가해보자.. 10이 5번반복될것이다..
        var arr = []
        for(var i = 0; i < 5; i++){
        arr[i] = function(){
        return i;
        }
        }
        i =10; <--------------이렇게 넣어주면 함수i는 가장최신값 10을 가져옴 최종적으로 10을 5번반복함.
        for(var index in arr) {
        console.log(arr[index]());
        }
        따라서 제대로 나오게 할려면
        함수에 인자로 i값을 넣어주고
        인자 i값을 함수내부에 존재하는 지역변수처럼 사용할수있도록
        내부 함수를 만들어 리턴값으로참조하면된다..(말로 설명하려니 어렵죠 ^^;)
        예를들어)
        arr[i] = function(id) { <----------2번 : id 에 인자값 i가 들어 옴
        return function(){
        return id; <------3번: 들어온 인자값을 함수내의 지역변수처럼사용할수있게 내부함수를 만들어
        } ----------------------리턴값으로 들어온 인자값을 가르킨다..
        }(i); <------1번: i 값을 인자로 넣어주고..
      • 노원신
        아직 초보라서 그런가 이해가 안되네요. ㅠㅠ
      • devHenry
        var와 let의 차이점을 공부해보시면 될듯합니다
        대화보기
        • 이동훈
          클로저 4/4 : 아래 코드가 잘 작동하는데...

          let arr = [];
          for (let i=0; i<5; i++) {
          arr[i] = function () {
          return i;
          }
          }
          for (let index in arr) {
          console.log(arr[index]());
          }
          실행결과 : 0 1 2 3 4
        • hanel_
          감사합니다^^
        • hanel_
          21.2.12
        • 주니어개발자
          클로저 넌 이제 내것이다.

          애초부터 최신 ecma의 let const 등을 사용해 block level scope 을 활용하고
          지역변수를 선언해 구분해 쓰면 깔끔하겠지만
          실제로 유지보수 업무를 하게 되면 예전 코드들은 var 키워드만 사용해
          전통적인 유효범위인 global scope와 function level scope만 두고 짜놓은 코드들이 많아서
          그것을 맘먹고 최신방식의 코드로 수정할 때도, 또는 부분적으로 수정할 경우에도 반드시 이해하고 활용할 수 있어야 할 개념
        • 강승
          감사합니다.
        • 박병진
          2020.10.24 완료
        • 박병진
          2020.10.24 완료
        • 20201012 완료

          4번 영상 다시 참고하기
        • Yongbeom Kwon
          완료
        • 물달
          준바이 라는 분 덕분에 4번째 영상에 대한 이해와 let에 대해서 알아 볼 수 있었네요 설명해주셔서 감사합니다. 가능하다면 문서에도 업데이트가 된다면 좋을 것 같네요
        • 김재원123
          감사합니다. 경우의 수를 따져보는것을 생각하지 못하였습니다. 감사합니다 좋은하루 보내세요 ^^
          대화보기
          • dasjnfal
            그렇죠, 귤님의 방식으로도 결과는 충분히 얻을 수 있지만 내부함수가 외부함수의 지역변수를 사용할 수 있다는 것은 알지 못하겠죠. 하지만 egoing의 예제에서는 내부함수에서의 id가 외부함수의 매개변수인 id를 공유하고 있다는 것을 알 수 있어요.
            대화보기
            • dasjnfal
              변수이름이 중복이라서 나는 오류인 것 같습니다. title은 factory_movie의 argument로 선언이 되어 있는 상태 입니다. get_title은 그 scope 내에 있구요. 그래서 _title은 다른 변수의 이름으로서 활용이 가능하지만 title은 오류가 날 것입니다. 어떤 오류가 나는지 정확하게 말씀해주시면 더 좋을 것 같아요!
              대화보기
              • 김동호
                생활코딩 자료가 2014년 이후로 변경되지 않아서 그런데 2015년 이후로 let과 const를 사용하면 위와 같은 문제가 발생하지 않습니다!
                대화보기
                • 준식
                  20200606 진행중
                  함수부터 어려워요~
                  한번 듣고 또 들읍시다~
                • dhemdas
                  function factory_movie(title){
                  return {
                  get_title : function (){
                  return title;
                  },
                  set_title : function(_title){
                  title = _title
                  }
                  }
                  }



                  이부분에서 첫번째 객체 get_title 함수에 매개변수를 설정을 하면, 예를 들어 function(title){return title} 이렇게 설정을 하면 왜 오류가 날까요ㅜㅜ 매개변수를 설정하고 안 하고의 기준이나 차이를 모르겠어요. 밑에 set_title은 타이틀을 변경하기 위해 _ title이라는 아무 매개변수를 먹여준다고 이해해 봐도 어렵네요 고수님들 부탁드립니다
                • 궁금한것이 있습니다!
                  0~4의 결과가 나올수 있게끔 혼자서 코드 연습을 해보다가 다음과 같이 작성하여도
                  똑같은 결과가 나온다는 것을 알았습니다.
                  제가 작성한 코드에서는 inner function을 사용하지 않았지만,
                  arr[i]가 함수가 아닌 결과값인 id만 저장하는 것처럼 보입니다.(즉, arr[i] = id)
                  이렇게 작성하여도 위에 있는 수업내용과 같다고 할 수 있는 건가요?
                  아니면 수업에서는 closure의 응용을 보여주기 위해 일부러 inner 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]);
                  }
                • 아기별
                  클로저가 지금까지 들었던 것 중에 제일 어려운 것 같아요..!
                  지금까지 여러 번 강의를 들어보고 댓글을 읽어보며 알게 된 점을 정리해보려고 합니다.
                  설명해주신 모든 분들, 이고잉쌤 정말 감사합니다! 혹시라도 틀린 부분이 있다면 알려주세요.

                  -------------------------------------------------------------------------------------------------------
                  //1. 결과값이 5가 다섯 번 뜬 이유
                  코드대로라면 결과값으로
                  0 1 2 3 4가 뜰 것 같은데
                  실제론 5가 5번 뜬다.

                  arr[i]는
                  function(){return i;}를 의미하고
                  그 함수에 들어있는 변수 i는
                  for 반복문이 다 돌고 나서 5로 정의된
                  전역변수 i를 데리고 온 것이라서 이런 현상이 생긴 것이다.

                  (흠..아무래도 return i 가 다섯 번 나열되는게 더 먼저고
                  그 뒤 i에 들어갈 값을 자바스크립트가 찾는데 그것이
                  for 반복문을 끝낸 var i의 값이 5라서 그 값을 집어넣어 그런 것이지 않을까 싶다)


                  //2. 처음 예상한 것처럼 결과값을 만들고 싶다면 : 클로저를 이용한다.
                  i가 arr[i]에 들어가서 arr[0~5]를 만들되
                  그 안에서 실행되는 함수는 for문에서 정의된 i=0; i<5; i++의 영향을 받지 않으려면
                  외부함수를 만들어 외부함수의 지역변수를 따로 정의하고,
                  내부함수의 변수가 for문을 도는 전역변수 대신 지역변수값을 끌어다 쓰게 해야 한다.

                  지금의 i가 외부변수가 아닌 이유는
                  arr[i]를 감싸고 있는 외부함수가 없기 때문이다.
                  따라서 익명 함수로 arr[i]=function(){return i}함수를 감싸줘서 외부함수의 역할을 하게끔 한다.


                  //3. 클로저 하기 위해 외부함수의 지역변수 따로 설정하기
                  하지만 여기에서 문제가 있다.
                  arr[i] = function(){
                  function(){
                  return i;
                  }
                  }();
                  }

                  외부함수를 따로 만들었다고 해도 이대로라면
                  for문의 i대신 따로 정의 내린 외부함수의 지역변수가 없으니
                  내부함수의 변수 i는 계속 for문에 정의되어 있는 전역변수 i값을 끌어다 쓸 것이다.

                  따라서 외부함수의 매개변수를 id로 바꿔주며 새롭게 지역변수를 정의한다.
                  그리고 내부함수의 변수를 외부함수의 지역변수를 따르게 하기 위해 i에서 id로 바꿔준다.


                  //4. 함수를 실행하면 생기는 일
                  이제 외부함수의 함수인자에 i를 집어넣어도
                  전역변수 i가 아니라 외부함수의 지역변수 id의 값이 되므로
                  i가 for반복문을 돌지 않게 된다.

                  그리고 내부함수의 변수는 외부함수의 지역변수를 끌어 쓰게 되어
                  for문을 돌지 않은 i값을 내보내게 된다.
                  따라서 결과값이 0 1 2 3 4가 나온다.


                  //정리를 하면
                  처음에 : 내부함수의 변수가 전역변수를 참조하던 현상이 있었다. (내가 원하던 건 이게 아니다!)

                  그러나 : 클로저(외부함수의 변수를 내부함수가 끌어다 쓸 수 있다) 덕분에 이런 현상을 막을 수 있다.

                  어떻게 하냐면 :
                  외부함수의 지역변수를 따로 정의한 뒤 내부함수의 변수와 이어줌으로써
                  전역변수와 내부함수의 변수와의 연결고리를 끊어주고
                  내부함수의 변수가 외부함수의 지역변수를 참조하게 한다.
                • ironia
                  감사합니다. 이 부분을 더 공부해야겠군요~^^
                • 브이에스코드
                  두 분 답변 감사합니다~
                • 브이에스코드
                  답변 감사합니다
                  대화보기
                  • 춤추는망고
                    만약에 말이죠...?

                    정말 보안이 철저한 회사에서 다니는데,

                    외부함수라는 회사건물의

                    내부함수라는 사무실에서 일을 하고있는 상황이라면,

                    회사건물 밖에있는 문서를 들고와서 일을 하는 것은 안되겠죠??

                    하지만, 사무실 밖이긴 해도

                    회사 안에 있는 문서를 써서 일을 하는 것은 문제가 되지 않을겁니다.

                    근무시간이 끝난 야근을 하는 시간이더라도요.

                    이때, 내부함수라는 사무실에서 일을 하는 사람은.

                    외부함수라는 회사의 직원이기 때문에, 외부함수의 문서를 쓸 수 있습니다.

                    회사라는 외부함수에 지정된 변수 ( 문서 ) 를

                    내부함수라는 사무실로 가져와서 쓸 수 있는 것.

                    이게 클로져라고 생각합니다.


                    작성해주신 코드가 작동을 하는 이유는

                    var arr2 = [ ] ; < 배열을 생성
                    for ( var i = 0 ; i < 5 ; i++ ) { < 5회 반복하는 반복문의 구성 생성
                    arr2 [ i ] = function ( id ) { return id ; } ( i ) ; }
                    ^ 매개변수 i 를 갖는 arr2 라는 객체에,
                    id 라는 매개변수를 갖는 함수를 담았고,
                    그 함수는 id 를 return 하라는 내용이죠.
                    그리고 그 함수에 i 라는 인자를 넣어 실행하라는 명렁이
                    위의 반복문 구절에 의해 반복되는 것입니다.

                    이렇게 작동을 해서 인데요.

                    여기는 회사와 사무실이라는 상황이 생기지 않았죠??

                    왜냐하면 작성해주신 코드는 하나의 함수(회사)만 포함하고 있으니까요.

                    이해가 되셨으면 좋겠습니당.

                    VSCODE 넘모 편하고~ >_<
                    대화보기
                    • 준바이
                      지금 작성하신 코드는 클로저가 적용되었다고 보기가 힘듭니다.

                      클로저는 내부 함수가 외부 함수의 맥락에 접근하는 개념이라고 살펴보았습니다.

                      반복을 다 벗겨내고 님이 작성한 코드를 볼까요?

                      var arr2 = [];
                      var i = 0 ;
                      arr2[0] = function(id){return id}(0);// 그냥 0라는 값이 arr2[4]에 들어감
                      i = i+1;
                      arr2[1] = function(id){return id}(1);// 그냥 1라는 값이 arr2[4]에 들어감
                      i = i+1;
                      arr2[2] = function(id){return id}(2);// 그냥 2라는 값이 arr2[4]에 들어감
                      i = i+1;
                      arr2[3] = function(id){return id}(3);// 그냥 3라는 값이 arr2[4]에 들어감
                      i = i+1;
                      arr2[4] = function(id){return id}(4); // 그냥 4라는 값이 arr2[4]에 들어감
                      i = i+1;

                      [ 반복 부분은 생략합니다 ]

                      즉... 질문자 분께서는 그냥 var arr2 = [0,1,2,3,4] 라는 숫자 배열을 만드신겁니다.

                      아마 function(id){return id}(i); 라는 IIFE라는 방식에 대해 생소하시다 보니 이해가 잘 안되신 것 같습니다. function(id){return id}(i);를 조금 이해가 쉽게 작성하자면

                      function(id){
                      return id
                      }

                      라는 함수를 만든 바로 그 자리에서 바로 호출하는 개념입니다. 그래서 끝에 (i)가 붙는 것이죠.
                      함수 호출할때 '함수명(보낼 값)'의 형태자나용. 자 그럼 이 함수를 무엇을 return 하죠? (i)를 통해 전달한 id값을 반환하겠죠. 그래서 그냥 숫자를 반환한 값이 배열에 들어갔던 겁니다.

                      그렇기 때문에 반복문을 통해 출력한 값이 0 1 2 3 4 인 것이죠!!

                      이고잉님이 보여주셨던 예제는 var arr2 = { 함수1,함수2,함수3,함수4,함수5 } 형태로 구성이 되며
                      각각은 외부 함수와의 맥락에 연결되어 있어서 출력 값이 0 1 2 3 4 였던 것 입니다.

                      이해가 조금 되셨나요??

                      # 클로저라는 개념은 초심자라면 확실히 조금 나중의 과제로 미뤄둬도 나쁜 선택을 아닌 것 같습니다. 저도 깊은 이해는 접어두고 개념적으로만 이해하고, 개발이라는 분야의 큰 그림을 보고자 진도를 좀 열심히 빼고 있어요 ㅎㅎ 화이팅 입니다
                      대화보기
                      • COCO
                        친절한 설명 감사합니다 ~ !
                        대화보기
                        • 브이에스코드
                          var arr2 = [];
                          for(var i = 0; i < 5; i++) {
                          arr2[i] = function(id) {
                          return id;
                          }(i);
                          }

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

                          마지막 예제 이렇게 수정해도 원하는 결과가 나오긴 한데, (0 1 2 3 4)

                          이렇게 수정한 것이 '클로저' 란 개념이 포함(사용)된 건지 아닌지는 잘 모르겠군요...

                          제 생각엔 원하는 결과를 얻기위해 수정된 것일뿐 '클로저'란 개념은 사용 안된 수정법인것 같은데

                          고수분들 답변 부탁드립니다.
                        • 아하
                          감사합니다. 이해가 쏙쏙 되네요. 강의하셔도되겠어요.
                          대화보기
                          • 준바이
                            4번째 영상에서 많은 분들이 이해가 잘 안가시는 것 같아 ( 저 또한 1시간 정도 이해하느라 구글링했네요. 이거도 작성하느라 30분 씀 ) 정리해본 것을 올립니다. 2개의 코드에 대한 분석입니다.

                            1. 문제가 되는 케이스

                            [코드 원본]

                            var arr = []
                            for(var i = 0; i < 5; i++){
                            arr[i] = function(){
                            return i;
                            }
                            }

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

                            [ 위의 원본에서 반복을 벗겨낸, 사실 상 동일한 코드 ]

                            var arr = [ ] ;

                            var i = 0 ;

                            arr[i] = function() { return i }; // 이 시점에서 arr속의 i 는 0 입니다.
                            i = i + 1; // i 는 1이 됩니다.

                            arr[i] = function() { return i }; // 이 시점에서 arr속의 i 는 1 입니다.
                            i = i + 1; // i 는 2가 됩니다.

                            arr[i] = function() { return i }; // 이 시점에서 arr속의 i 는 2 입니다.
                            i = i + 1; // i는 3이 됩니다.

                            arr[i] = function() { return i }; // 이 시점에서 arr속의 i 는 3 입니다.
                            i = i + 1; // i는 4가 됩니다.

                            arr[i] = function() { return i }; // 이 시점에서 arr의 i 는 4 입니다.
                            i = i + 1; // 바로 이 문장 때문입니다. 반복문에서는 4번째 반복을 마친 후 i++을 한번 더 실행해서 그 다음 조건을 체크 할 때 i가 5보다 작음을 판단하게 되는데 이 코드로써 i 는 5가 됩니다. 계속 보시죠.

                            // for(var index in arr) 이라는 문법은 기본적으로 index에 arr의 길이만큼을 0에서 부터 대입시킵니다. 즉, 우리 arr의 길이는 5개니까 index에는 순차적으로 0 1 2 3 4 가 대입이 되겠죠. 그래서 반복문을 벗겨내면요,

                            console.log(arr[0]()); // 5
                            console.log(arr[1]()); // 5
                            console.log(arr[2]()); // 5
                            console.log(arr[3]()); // 5
                            console.log(arr[4]()); // 5

                            // 이렇게 되는데요, 이 과정에서 각각 함수를 호출할 때(arr[0]() ~ arr[4])처럼)는 function() {return i}에서 그 i는 그냥 단순히 var i라는 전역변수를 참조하게 됩니다. 그래서 위에서 마지막으로 증가한 값인 가장 최신의 i값인 5가 5번 출력되는 것이죠.

                            # 참고로, 제가 확인해보니 이런 식으로 사용할 때는 배열을 쓰면 구글 개발자 도구가 버그를 뱉더군요. 그래서 var arr = [ ] 이 아니라 var arr = { }라 해줘야 버그가 안나더라고요.
                            # 아참 var도 요즘 안씁니다. ( let 에 대해 구글링해서 공부해주세요, block scope와 global scope, function scope 개념 잡으시는 거 선택이 아니라 필수에염)

                            2. 클로저가 적용된 코드.

                            [ 코드 원본 ]

                            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]());
                            }

                            [ 위의 원본에서 반복을 벗겨낸 코드 ]

                            위의 설명을 통해 똑같이 유추할 수 있는 부분은 설명을 생략합니다.

                            var arr = [ ]

                            var i = 0 ;

                            arr[i] = function(id){
                            return function( ){
                            return id;
                            }
                            }(i); // 가독성을 위해 이거만 들여쓰기를 할게요. 자자 이게 1번의 문제가 되는 코드와의 차이점은 외부함수와 내부함수를 적용해서 함수안에 함수를 만든 점과, IIFE(https://sseambong.tistory.com/250 , 참고하세요 읽는데 얼마 안걸림)라는 개념을 적용하여서 함수를 즉시 호출하는 방식을 썼다는 점 입니다. 여기서 id를 주목해주세요. i라는 매개변수를 function(id)가 받습니다. 그와 동시에 그 밑에 바로 var id = 전달받은 i라는 값; 라는 문장이 추가 된다고 보셔도 좋아요. ( 더 자세한 메커니즘을 알고 싶다면 '함수 매개변수 전달 과정에서 메모리 복사와 참조' 라는 주제로 공부해보시는 걸 추천합니다. ) 그러면 사실상 함수안에 지역변수를 만든 꼴이 되는거죠 !! 이로써 코드 마지막에 arr[i]()라는 함수는 전역변수인 var i를 리턴하는 함수가 아니라 var id라는 지역변수를 리턴하는 함수가 된 것 이겠죠.

                            i = i +1;

                            arr[i] = function(id){ return function( ){ return id; }}(i); // var id는 1
                            i = i +1;

                            arr[i] = function(id){ return function( ){ return id; }}(i); // var id는 2
                            i = i +1;

                            arr[i] = function(id){ return function( ){ return id; }}(i); // var id는 3
                            i = i +1;

                            arr[i] = function(id){ return function( ){ return id; }}(i); // var id는 4
                            i = i +1; // 아까와의 차이점 이제 아시겠죠? 여전히 이 i는 5겠지만 앞으로 출력할 내용에는 전혀 영향을 미치지 않습니다.

                            console.log(arr[0]()); // 0
                            console.log(arr[1]()); // 1
                            console.log(arr[2]()); // 2
                            console.log(arr[3]()); // 3
                            console.log(arr[4]()); // 4

                            감사합니다. 조금이라도 도움이 되었으면 좋겠습니다. 본인이 이해가 안간다면 더 많은 시간을 투자해서 알아내야 한다고 생각합니다. 어떨 때는 되고 어떻때는 안되고 하는 것을 파악하는 게 프로그래밍 고수로 가는 정도이자 가장 빠른 길로 믿고서 열심히 공부합시다!!
                          • 양아치네 에게
                            불쌍한 친구네..
                            이고잉님은 국가에서 상을 줘도 모자란 분이시다..
                            이 분야에 이정도 재능기부하는 분이 없어.
                            너의 부족한 이해력과 나태한 자세를 탓해라. 이해가 안가면 다시 듣던가
                            구글링해서 몇 페이지를 뒤져서라도 이해를 해야지 남탓이여 어디서.
                            그런 자세로는 그 어떤 일을 해도 항상 그 말만 되뇌이겠네.
                            부디 자기자신을 되돌아 보고 변화의 기회로 삼길 바란다.
                            대화보기
                            • 머가리
                              인간적으로 졸라 쉬운데 이해가 안되면 본인 머가리를 탓해야지 강사를 탓해 ㅋㅋ
                              코딩말고 막노동하면서 살아야할 인간이 주제에 안맞는 짓을 하려니... ㅉㅉ
                              대화보기
                              • 현역 개발자
                                저는 전문 개발자로서 15년째 주로 대기업 오라클 ERP/DB 설계/개발에 종사하고 있습니다.
                                egoing 님의 강의를 항상 감사한 마음으로 보고 있습니다.
                                어딜 가든 가르쳐주는 사람에게 고마운 걸 못 느끼고 징징거리는 양아치 같은 인간들이 있습니다.
                                그런 인간치고 실력 있는 사람은 아직 못 봤습니다.
                              • 설명충
                                나 이해 안되서 그러는데 니가 좀 더 잘 설명해 주면 안되겠니? 안되지?_너같은 애들 특징이 걍 실력도 뭣도 아무것도 없는데 정신나간것 처럼 분위기 흐리고 가는게 종특이라.
                                대화보기
                                • 호날두
                                  손흥민ㄴ님 박지성님.. 진짜최고된다..
                                • 양아치냐
                                  맥락없이 웬 욕질
                                  설명 더 잘하든지
                                  처 자빠져 자든지
                                  그냥 구경 하든지
                                  여긴 좀 끼지마라
                                  대화보기
                                  • sento
                                    질문이 잇습니다. 왜 에디터에서는 안하시고 콘솔에서만 하시는지용~~~~ 궁금해용!~~~ 에디터에 안하니 솔직히 저같이 초짜는 이해가 반만 되서요~
                                  • 굼벵이
                                    완료
                                  • 오현주
                                    2019.12.18 수강
                                  • 홍주호
                                    20191026 완료
                                  • 정홍
                                    완료
                                  • 박창신
                                    완료
                                  • 싸커홍
                                    나중에 다시한번 복습해야겠네요
                                  • asdf
                                    var은 function scope이고
                                    let, const는 block scope 입니다.
                                    반대로 쓰셨네요
                                    대화보기
                                    • 스코프
                                      var의 scope가 function scope이고
                                      let, const가 block scope입니다.
                                      자바스크립트 원래 block scope가 없었는데 es6에서 let과 const가 생기면서 개념이 생긴것입니다.
                                      대화보기
                                      • 마지막 부분에서, scope 의 개념으로 접근했을 때,
                                        var 의 scope (block-scope)
                                        let 의 scope (function-scope) 서로 다른 특성으로 으로 구분되기 때문에,
                                        var 을 let으로 바꾸면 정상적인 출력(0 1 2 3 4) 를 얻을 수 있습니다.

                                        const arr = []
                                        for(let i = 0; i < 5; i++){
                                        arr[i] = function(){
                                        return i;
                                        }
                                        }
                                        for(let index in arr) {
                                        console.log(arr[index]());
                                        }
                                      • 박순기
                                        손흥민님 감사합니다... egoing님이 이렇게 설명했으면 대부분 사람들이 빨리 이해를 했을텐데..
                                        대화보기
                                        • 마지막 영상에서 잘못된 코드가 왜 5를 다섯 번 찍어내는지 정리해보았어요! 이해하는데 한참 걸렸는데
                                          잘못된 부분 있으면 알려주시면 감사하겠습니닷.
                                          --------------
                                          var arr = []
                                          for(var i = 0; i < 5; i++){
                                          arr[i] = function(){
                                          return i;
                                          }
                                          }
                                          for(var index in arr) {
                                          console.log(arr[index]());
                                          }
                                          --------------------
                                          - 위 코드에서 루프가 다 돌고 난후 `i++`이 실행되어 최종적으로 i값은 5이다
                                          - 첫번재 반복문에서 arr[index]에 담긴 것은 특정한 값이 아니라 함수이다.
                                          - console.log(arr[index]());를 호출했을 때, 외부의 컨텍스트에 접근할 수 있을 것으로 기대하였다.
                                          - 하지만 for문의 i는 외부함수의 변수가 아니었다. 훼이크!
                                          - 따라서 단순히 arr[index]에 담긴 함수가 5회 실행되어 현재의 i값인 5를 출력하였다.
                                        버전 관리
                                        egoing
                                        현재 버전
                                        선택 버전
                                        graphittie 자세히 보기