인프런 커뮤니티 질문&답변

KH K님의 프로필 이미지
KH K

작성한 질문수

생활코딩 - 자바스크립트(JavaScript) 기본

클로저의 응용

첫번째 예시문에서 값이 왜 5가 5번 반복되는지 궁금합니다.

해결된 질문

작성

·

462

0

var arr = [ ]

for(var i = 0; i <5; i++){ arr[i] = funtion() { retun i; } } 여기서 arr[i]는 function의 값을 받아서 i의 값이 5가 되기 전까지 i의 값을 반환한다는 뜻으로 이해했습니다. 그럼 0,1,2,3,4 겠죠.

그리고   for (var index in arr) { console.log(arr[index]()); } 이것은 arr 라는 배열의 모든 값(index)을  위의 function값으로 반환된 0,1,2,3,4를 콘솔에 표시한다는 것으로 이해했습니다. 그래서 마지막 예시에서 0,1,2,3,4 값이 출력 됐겠죠. 그런데 그 대신 5가 5번 출력됐습니다.

말씀하신대로 for의 i의 값은 function의 외부변수 i값이 아니기 때문이라는 것 까지는 이해했습니다. 그래서 잘못 출력된 것이겠죠. 근데 왜 하필 그 값이 5인지는 이해가 되질 않습니다. 그래서 이후에 설명하시는 function(id){ return function () { return id; } } 이것 또한 이해가 되질 않습니다. 외부함수의 매개변수 id값은 내부함수에서 반환된 id값을 칭하는 것으로 이해했는데 그 이후(i);를 바로 실행시키면 외부함수의 매개변수인 id값이 (i)를 통해 i로 변하여 그게 arr배열의 i 값이 된다는 것인가요?

그렇다면 내부함수 id의 값이 왜 0,1,2,3,4가 되는지에 대한 설명이 없어서  또한 이해가 되질 않습니다. 제가 너무 초보라서 배경지식이 없는 상태에서 듣는거라 그런것인지...ㅠㅠ; 과거 수학을 포기했을 때 하나를 모르면 그 이후의 것이 이해가 안되던 기억이 있어 대충 듣고 넘어가는 것을 못합니다.. 이게 이해 될때까지 하루 반나절을 돌려보며 이해하려고 노력중인데 이것 만큼은 이해가 안되어 질문으로 남깁니다. 답변 꼭 부탁드릴게요 ㅠㅠ;

답변 3

3

5라는 값이 5번 나온 것은 제 생각에는...함수의 정의가 대입된 것과 함수가 호출되어 대입된 것의 차이가 아닐까 합니다.

arr[i] = funtion() { retun i; }

arr[i] = function (id) { return function () { return id;}}(i); << 마지막에 (i)가 관건인 것 같네요.

첫번째 것은 함수의 정의만 대입된 상태이고, i 값은 아직 정해지지 않은 상태입니다. arr[index] << 이놈이 실행될때 i값이 정해지게 되겠죠.

두번째 것은 arr[i] = function(i); 와 같은 의미가 되어서 function에 파라미터로 0, 1, 2, 3, 4 가 전달된 결과가 id에 설정되어 대입되는 것으로 생각됩니다.

맞을지는 모르겠지만.....ㅎㅎㅎㅎ

참고로 저는 38입니다. c++만 12년하다가 이제서 javascript를 배우고 있답니다. 뭔가 많이 다르네요. 머리가 굳어서 그런지 잘 이해도 안되고;;; 이런 저도 있으니 30살이라고 늦은건 아닙니다. 힘내세요.^^

2

우선 이런 문제는 var 의 문제점이라 볼 수 있습니다.
es6(es2015)부터는 이런 문제때문에 var 대신 const, let 을 쓰자고 지향하고 있습니다.

for (var i = 0; i < 5; i++) {}
console.log(i);

우선 위에 방식으로 for 문 안에 var i를 선언하고 바깥에서 console.log(i) 를 호출하면 이상하게
오류 없이 호출되는 걸 볼 수 있습니다.
그 이유는 var 선언 방식이 block scope가 아니라 function 단위 scope이기 때문에
for문이 끝났음에도 여전히 전역변수로써 유효하기 때문입니다.
전역변수로 선언되어 버리는 부분이 어떤 문제를 일으키는지 아래 코드를 보면서 살펴보죠. 

* 영상에서의 코드

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

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

                                                                                   ↓

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

...

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

이런식으로 배열내 각 인덱스에 할당되겠죠. 하지만 return 값은 할당될 때의
i 값이아니라 전역변수 i 를 참조하고 있기 때문에 이 함수들을 호출하면 계속해서
전역변수 i 의 최종 값인  5를 불러오게 되는 겁니다.
첫번째 for 문에서 루프가 끝나면서 전역변수 i의 값이 이미 5가 되었으니까요.

* 클로저를 사용하면 정상작동 하는 이유

for (var i = 0; i < 5; i++) {
  arr[i] = function (index) {  // index는 parameter이며, 전달인자로 받은 i 값이 들어있다.
    return function () {
      return index;
    };
  }(i);  // 전달인자(argument)로 i를 주고있다.
}

for (var func of arr) {
  console.log(func());
}

클로저(closure)를 사용하여 전달인자(argument)로 i 값을 주면 배열에 각 함수가 할당될 때 그 때의 i 값을 매개변수(parameter)로 받기 때문에 지역변수를 사용한 것 같은 효과가 나게되는 것이죠.

이해가 안되어서 헤메고 있었는데, 명쾌한 설명 감사드립니다.

2

KH K님의 프로필 이미지
KH K
질문자

이 글을 적고 다시한번 영상을 돌려보며 어느정도 이해가 됐습니다. 혹시라도 저와 비슷한 케이스가 있으실 것 같아 글로 남깁니다. 하지만 맨 처음 왜 5라는 값이 5번 나왔는지는 아직까지 모르겠습니다. ㅠㅠ

var arr = []

      for(var i = 0; i <5; i++){ // 1. for문이 실행되면 함수가 실행이 됩니다.

        arr[i] = function (id) { //  3. 여기서 내부함수를 리턴합니다. 리턴을 하면 그 함수는 수명을 다합니다. 그리고 arr[ i ]라는 배열에 내부함수가 들어가게 됩니다. arr [ function() { return id; } ]

          return function () { //   4. 외부함수의 매개변수가 id에서 for문에 있는 i로 입력되어 있으므로 내부함수의 id값을 리턴하라고 적힌 구문이 for문의 i값을 리턴하게 됩니다. 클로저로 인해 죽어있는 외부함수의 값에도 접근 할 수 있기 때문이죠. 그 결과 for문 i의 첫번째 값인 0이 arr배열에 입력되게 됩니다. 이후 i값은 for의 i++때문에 1씩 커지겠죠. 이걸  for 반복문으로 i값이 5보다 작을 때 까지 반복하게 되겠죠?

            return id;

          }

        }(i); //2. 외부함수의 인자 값으로 i가 들어가게 됩니다. i = 0이죠?

5. 그래서 결과적으로

  var arr = [0,1,2,3,4]  가 됩니다.

6. 이후 나오는

for (var index in arr) {

        console.log(arr[index]()); //arr 배열의 값을 ();함수로 불러내면 0,1,2,3,4가 불러와 지겠죠. 사실 여기도 헷갈립니다 아직 ㅋㅋ 이전 for문에 있던 함수를 ();이것으로만 불러 낼 수 있는 이유를 모르겠어요. 일단 불러왔다 치고 보면 arr 배열의 모든 인자들을 각각 출력시키겠죠.

      }

7. 그래서 이걸 완벽히 똑같진 않지만 같은의미로 쉽게 풀어보면

var arr = [0,1,2,3,4]

      for (var index in arr) {

        console.log(arr[index]);

      }

이것과 같은 의미가 되는겁니다;

이렇게 뭔가 벽에 막히는 느낌이 들 때 마다 30살에 이걸 시작해도 될 까 싶기도 합니다만, 몸쓰는 일만 하여 남은거라곤 조금 버틸수 있는 푼돈과 망가져버린 몸이란걸 생각하면 어떻게든 배워보려고 합니다.

저보다 나이가 많으신 분들도 계시겠죠. 하지만 코딩을 배우려는 대다수는 저보다 어릴거라고 생각합니다. 늦었다고 생각하지 마세요. 사람수명은 점점 늘어갈 것이고 결국 끝까지 가는 사람은 나이가 어떻든 간에 개발자의 실력을 가지게 될 것입니다. 사람의 나이는 얼마나 늙었는지 알려주는 지표가 아니라 그 시간동안 어떤 것에 박식한 사람이 되었을까 궁금해 하게 하는 지표입니다. 뭐 이런데 이런걸 적는지 모르겠습니다.. 다 적고나니 이상한 이야기를 하고있군요 ㅋㅋ; 결코 포기하지 맙시다!

KH K님의 프로필 이미지
KH K

작성한 질문수

질문하기