Javascript – scope 이야기 클로저(Closure) – 한 번 더 정리 2/2

Javascript – scope 이야기 : 클로저(Closure) #2/2

지난번에 알아본 클로저 개념을 다시 상기시키면서 아래 예제를 살펴보자.

클로저 함수는 외부 함수의 실행이 끝나더라도 외부 함수 내 변수를 사용할 수 있다.
클로저는 이처럼 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있게하는 폐쇄성을 갖는다.아래는 서핑하다가 클로저의 잘못된 이해로 실수를 범하기 쉬운 사례 샘플이라하여,이해를 돕고자 그대로 가져왔다.
var myArray =new Array(5);

for(var i=0; i<5;i++)  // 외부함수
{
console.log(i);   // 0 ,1, 2 ,3 ,4
myArray[ i ] = function() {  return  i }    // 내부함수
}

// 위에 코드를 예상해보면,
// myArray[0] = function() { return 0};
// myArray[1] = function() { return 1};
// myArray[2] = function() { return 2};
// myArray[3] = function() { return 3};
// myArray[4] = function() { return 4};

for(var i in myArray)
{
console.log(myArray[i]());
}

//  출력을 예상해 본다면,
// console.log(myArray[0]); // 예상출력 0 – 실제 출력 5
// console.log(myArray[1]); // 예상출력 1 – 실제 출력 5
// console.log(myArray[2]); // 예상출력 2 – 실제 출력 5
// console.log(myArray[3]); // 에상출력 3 – 실제 출력 5
// console.log(myArray[4]); // 예상출력 4 – 실제 출력 5

잘못 이해하고 있는 관점에서보면 myArray [0~4] = function() { return 5 }; 를 한
느낌이 들것이다.

왜 이런결과가 나올까 이유를 알고나면   01,2,3,4, 출력을 예상한것이 이상하다는것을 알게 될것이다.

지난번 시간에 이야기 했듯이 실제로 함수(변수)가 사용하는 시점에서,
그 변수를 바라보고 있는 변수 참조에 대한 이야기를 했었다.

for(var i=0; i<5;i++)  
{
     console.log(i);   // 0 ,1, 2 ,3 ,4
     myArray[ i ] = function() {  return  i }  
}

외부함수 for 에서 선언된,  i 변수를 , 내부 함수  myArray[ i ] = function() {  return  i }   에서 사용이 되는데, 여기서는 { return i } 를 말한다.

위의 for 의 지역변수  i 는 for  문을 벗어나려면 i < 5 조건을 만족해야하는데,
반복하여 증가하면서 i 가 5 가되어서야 루프를 탈출하게 된다.


// 출력 for 문
for(var i=0; i<5;i++)  
{
     console.log( myArray[x]() ) ;
   
}

출력 for 문에서 myArray[x]() 함수를 호출 하면서, 위에 지역변수 i 를 “참조” 하게 되는데
for 문을 벗나오면서 i 가 마지막으로 가지고 있는 값은 “5” 가 되어 그 참조된 주소에서

계속 5를 가져오는 상황이 일어 나는것이다.

좀 더 이해를 쉽게하기 위해 , 코드를 수정해보자

for( var i=0; i<5;i++)
{
   myArray[i] = function() { return i }
if ( i == 2)   i = 100;    // 0, 1 , 2 일때 i 를 100 으로 셋팅하여 루프를 탈출해보자
}

// 다시 위에 코드를 예상해보자 어떻게 보이는지
// myArray[0] = function() { return i };  // 참조되는 i 현재 0 
// myArray[1] = function() { return i };  // 참조되는 i 현재 1  
// myArray[2] = function() { return i };  // 참조되는 i 현재 2 ,  i = 100 셋팅 탈출
// myArray[3] = “”;
// myArray[4] = “”;

for(var a in myArray)
{
    console.log(myArray[a]());
}

그럼 출력은?

위의 소스를 다시한번 살펴보자,
변수의 레퍼런스(참조)개념으로 살펴보면 아래와 같다.

for( var i=0; i<5;i++)
{
   myArray[i] = function() { return i }
if ( i == 2)   i = 100;
}


i = 0 일때 ( 변수 i를 참조하는 느낌 . 값 참조가 아님 X)
myArray[0] = function() { return 0 };

i = 1 일때 (변수 i를 참조하는 느낌. 값 참조가 아님 X)
myArray[0] = function() { return 1 };
myArray[1] = function() { return 1 };

i = 2 일때 ( 변수 i를 참조하는 느낌. 값 참조가 아님 X)
myArray[0] = function() { return 2 };
myArray[1] = function() { return 2};
myArray[2] = function() { return 2};

if (i == 2) i = 100;

for  문의  i < 5 조건을 탈출하는 순간은 i == 2 일때 i  가 100 이 되고, 다음처리때 탈출하
게된다. 그럼 for 문을 탈출했을때 myArray 함수의 i 값은 다음과 같이 i 를 참조하고 있다.

myArray[0] = function() { return 101 };
myArray[1] = function() { return 101};
myArray[2] = function() { return 101};

그래서 결과는,
101  // index 0
101  // index 1
101  // index 2

(100 아니고 101 인 이유는 i++ 를 먼저 실행하고  i < 5 조건을 비교하기때문)

을  3 번 출력하게된다. (for ~ in  [3] , [4] 번째 배열은  undefined 되어서 제외되었다.)

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다