Javascript로 개발하다보면, 처음에는 아주 쉽고 재밌게 느껴지며 너무 편하다고생각이 된다.

그러나 일정수준 이상되면 첫번째 한계에 부딪히게 되는데 그게바로 "Closure" 이다.

심지어 clousre에 대한 job interview 대답에 따라 $40k 까지 연봉이 차이가 날수도 있다는 blog posting까지 보았다.

(https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36)

(뇌피셜일수도 있으니 주의하자)

그럼 이토록 중요한 클로저가 무엇인지 다시한번 상기하고 필요성에 대해서 얘기해보고자 한다.

 

 

Closure

 먼저 클로저를 얘기하기전에 var에 대해서 이야기해보자, var로 선언된 변수는 기본적으로 function scope 내에서만 사용되어진다. 

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

 

내가만약 위의 함수를 오류가 없이 동작시키려면 global scope를 사용해야 할것이다.

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

 

지역변수는 보통 function이 끝나게 되면 메모리에서 사라진다.

그렇다면 우리는 local variable을 계속 참조 할 수 없을까? 이를 closure가 답변해준다.

 

 

클로저는 쉽게말해 persistance한 local variable scope이다. (persistance = 영속적인 한글로 표현하면 좀 어색해진다.)

클로저는 코드의 실행이 function 밖으로 이동했음에도 불구하고 지속되는 persistance local scope이다.
더 쉽게말해서 function scope 밖에서도 그 local variable에서 변수를 reference 할 수 있게 해준다. 
(객체지향적 설계를 가능하게 한다.)

다음을 코드를 보면 더 이해가 잘 될것이다.

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  var add = function() {
  	a += 1;
  }
  return {inner,add}; // this returns a function
}

var fnc = outer(); // execute outer to get inner 
fnc.inner();
fnc.add();
fnc.inner();

//output
//1
//2

위 코드에서처럼 a는 local variable임에도 불구하고 영속성을 갖는다. 이게 클로져이다.

JavaScript에서는 함수가 처음 선언 될 때 var a가 hoisting 되고, 함수가 계속 존재하는 한 var a도 지속되어진다.

a는 outer scope에 속한다. inner scope는 outer scope에 대한 참조가 있다. fnc는 inner scope를 가리키는 변수다. fnc가 지속되는 한 a또한 사라지지 않고 존재한다. closure 안에 있다.

이를 좀더 유식하게 말하면 "특정 함수가 참조하는 변수들이 선언된 렉시컬 스코프(lexical scope)는 계속 유지되는데, 그 함수와 스코프를 묶어서 closure 라고한다.

 

 

실질적인 closure에 관한 예제

먼저, 우리가 버튼을 클릭할때마다, 버튼이 클릭된 횟수를 세는 기능을 만든다고 가정해보자.

<button onclick="updateClickCount()">click me</button>  

 

1) Global variable을 쓰면 가장 쉽게 해결가능하다.

var counter = 0;

function updateClickCount() {
    ++counter;
    // do something with counter
}

 

그러나 counter라는 글로벌변수는 쉽게 노출되며, updateClickCount라는 함수의 호출없이 ++ 시킬수 있다.

 

2)그러면 counter function scope 내부로 옮긴다면?

function updateClickCount() {
    var counter = 0;
    ++counter;
    // do something with counter
}

counter는 항상 1로 될것이다. counter는 persistance한 local variable 이 아니기 때문이다.

 

3)Nested functions를 쓰면?

function countWrapper() {
    var counter = 0;
    function updateClickCount() {
    ++counter;
    // do something with counter
    }
    updateClickCount();    
    return counter; 
}

 당신이 외부 scope에서 updateClickCount 함수에 접근할수 있고, counter=0라는 선언을 한번만 호출할 수 있다면, 가장 좋은 방법일 것이다.

 

정답) Closure가 출격한다면 어떻게 될까? C L O S U R E ! (with IIFE)

 var updateClickCount=(function(){
    var counter=0;

    return function(){
     ++counter;
     // do something with counter
    }
})();

 

위처럼 한다면 우리가 처음 의도한대로 동작할 것이다.
local variable을 영속성을 갖게할수 있고 또 local variable을 객체지향적으로 encapsulation 할 수 있게된다.

이에 더하여 counter변수는 global scope에서 hoisting 되지 않으므로 변수의 충돌 또한 방지해준다.

 

<script>
var updateClickCount=(function(){
    var counter=0;

    return function(){
      ++counter;
      document.getElementById("spnCount").innerHTML=counter;
    }
  })();
</script>

<html>
  <button onclick="updateClickCount()">click me</button>
    <div> you've clicked 
  		<span id="spnCount"> 0 </span> times!
  	</div>
</html>

 

 

https://stackoverflow.com/questions/2728278/what-is-a-practical-use-for-a-closure-in-javascript

 

What is a practical use for a closure in JavaScript?

I'm trying my hardest to wrap my head around JavaScript closures. I get that by returning an inner function, it will have access to any variable defined in its immediate parent. Where would this be

stackoverflow.com

 

 

PS. 우리는 let으로 문제를 해결했던 for 문 딜레마도 closure를 통해 해결할 수 있다.

var i = 0;
for(i = 0; i<3; i++) {
	(function(index){
    	cosnole.log(My value : index);
    }(i))
}

 

 

+ Recent posts