반응형

클로저(closure)는 지역변수를 (내부함수(inner function)안에 있는 변수) 전역변수(외부함수(outter function)처럼

살아있게끔 만들어줍니다.

내부함수가 외부함수의 맥락에 접근이 가능한것을 말하는것이죠. (Hoisting)

 

1
2
3
4
5
6
7
8
function outter() {
  var local = 'local'// 외부함수에 변수를 선언합니다.
  function inner() { // inner()는 외부함수 안에 선언된 내부함수입니다.
    alert(name); // 외부함수에서 선언된 변수를 내부함수에서 호출합니다.
  }
 inner();
}
outter();

 

See the Pen GRgvJmJ by LeeSiHwang (@leesihwang) on CodePen.

(Run Pen 클릭 시 alert가 실행됩니다)

 

외부함수 내에서 내부함수가 선언되고 호출이 되었습니다.

이것을 실행이 되는 관점으로 보자면 

 

1. 내부함수 안에서 변수 local을 찾는다. ( scope )

2. 자신의 함수안에서 변수 local을 찾지 못하여 외부함수의 스코프에서 변수 local을 찾는다.

3. 변수 local을 찾았다 ( 내부함수가 외부함수의 변수에 접근하였다 )

위에서 말씀드렸듯이 내부함수가 외부함수의 맥락에 접근이 가능한것 입니다.

 

2. 클로저(closure)의 활용

내부함수는 외부함수의 지역변수를 참조할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근 할 수 있습니다. 이런것을 클로저라고 합니다..

클로저가 유용하게 사용되는 경우는 다음 예제와 같이 변경된 상태를 유지/기억 하는 것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    function outterFn(){
        var inner = 0;
        var innerFn;
        innerFn = function(){ 
            console.log(inner++); 
        }
        return innerFn;
    }
    var nestFn = outterFn();
    nestFn(); // 0
    nestFn(); // 1   
    nestFn(); // 2   
    nestFn(); // 3   
    nestFn(); // 4   

 

1. outterFn 함수는 실행되고 innerFn을 반환하고 사라졌습니다.

2. innerFn 즉 내부함수는 자신이 찾았던 변수inner를 기억하는 클로저입니다.

3. 내부함수는 자신이 찾았던 변수inner를 필요로하며, 내부함수가 기억하는 Lexical환경의 변수inner는 사라지지 않고, 현 상태를 기억합니다.

4. 외부함수를 호출하면, 변수inner의 값이 변경됩니다. 

변수 inner는 클로저에의해 참조되고 있기 때문에 사라지지않고 계속 유지되며, 자신이 변경된 상태를 계속해서 유지합니다.

 

2. 클로저(closure)의 은닉화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<p>사과 1박스</p>
<p id="count">0</p>
<button id="plusNum">증가</button>
<button id="minusNum">감소</button>
<script>
    var privateNum = 0;
 
    function plus(){
        privateNum++;
        document.getElementById("count").innerText = privateNum;
    }
    function minus(){
        privateNum--;
        if(privateNum <= 0){
            privateNum = 0;
        }
        document.getElementById("count").innerText = privateNum;
    }
    document.getElementById("plusNum").addEventListener("click",function(){
        plus(); 
    });
    document.getElementById("minusNum").addEventListener("click",function(){
        minus(); 
    });
</script>

 

See the Pen RwNZPqr by LeeSiHwang (@leesihwang) on CodePen.

이렇게 코드를 작성한다해도 별문제없이 작동합니다.

하지만 이 코드는 addEventListener가 작동하기 이전에 count의 값이 반듯이 0이여야합니다.

변수 privateNum은 전역변수이기 때문에 언제든지 누구나 접근,변경이 쉽습니다.

변수 privateNum의 의도치않은 변경은 오류를 불러올 수 있기 때문에, 이 privateNum은

함수가 관리하는것이 좋습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<p>사과 1박스</p>
<p id="count">0</p>
<button id="plusNum">증가</button>
<button id="minusNum">감소</button>
<script>
    var plusMinus = (function(){
        var privateNum = 0;
        return{
            plus : function(){
                privateNum++;
                document.getElementById("count").innerText = privateNum;
            },
            minus : function(){
                privateNum--;
                if( privateNum <= 0 ){
                    privateNum = 0;
                }
                document.getElementById("count").innerText = privateNum;
            }
        }
    })();
 
    document.getElementById("plusNum").onclick = plusMinus.plus;
    document.getElementById("minusNum").onclick = plusMinus.minus;
</script>


  See the Pen https://codepen.io/leesihwang/pen/gObxpyL">
  gObxpyL by LeeSiHwang (https://codepen.io/leesihwang">@leesihwang)
  on https://codepen.io">CodePen.


이렇게 해결이 가능합니다.

그럼 만약에 단순히 변수 privateNum을 지역변수로 클로저 없이 사용한다면 어떻게 될까요?

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<p>사과 1박스</p>
<p id="count">0</p>
<button id="plusNum">증가</button>
<button id="minusNum">감소</button>
<script>
    function plus(){
        var privateNum = 0;
        privateNum++;
        return document.getElementById("count").innerText = privateNum; 
    }
    function minus(){
        var privateNum = 0;
        privateNum--;
        return document.getElementById("count").innerText = privateNum; 
    }
 
    document.getElementById("plusNum").addEventListener("click",function(){
        plus();  
    });
    document.getElementById("minusNum").addEventListener("click",function(){
        minus();  
    });
</script>

이렇게 코드를 작성하고 실행해봅니다.


  See the Pen https://codepen.io/leesihwang/pen/dyPzoxo">
  dyPzoxo by LeeSiHwang (https://codepen.io/leesihwang">@leesihwang)
  on https://codepen.io">CodePen.


변수 privateNum이 plus함수와 minus함수와 서로 다른 변수 privateNum으로 인식이되어 따로놀고있으며,

함수 실행 후, 클로저가 없기때문에 변수 privateNum이 유지되거나 기억되지못해 

plus버튼의 경우 0에서 1로만, minus버튼의 경우 0에서 -1로만 값이 유지되는것을 확인할 수 있습니다.

반응형

+ Recent posts