본문 바로가기
갬발자의 프로그래밍/Javascript

closure(클로저)

by 코라제이 2020. 1. 13.

클로져는 내부 함수의 렉시컬 환경 컴포넌트에서 외부 렉시컬 환경 컴포넌트를 참조하고 있게 되면서 사용할 수 있을 것을 말하게 된다. 

 

function a(){
    const name = 'a component';
    function b(){
        console.log(name);
    }
    return b;
}

const c = a();
console.log(c());//a component

 

위에서 보게 되면 내부 함수 b()가 외부 함수 a()의 변수 name을 참조해 사용된다. 이미 a()의 라이프 사이클은 c에게 b()를 반환하고 사라졌다. 하지만 c는 마치 함수 a()의 변수 name를 사용이라도 하듯 접근할수있다.

이것은 렉시컬 환경 스코프로인해서 함수가 정의된 곳에따라 상위 스코프의 참조가 가능해지기 때문이다.

 

클로저를 이용하면 외부 함수에서 정의한 변수를 외부에서 직접 접근하지 못하게 하며 은닉화를 시키고 캡슐화를 할 수 있다. 다음은 소리를 조절하는 함수이다

 

const volume = function() {
  let volume = 0;
  return {
    up: function() { volume++; },
    down: function() { volume--; },
    current: function() {
        return volume;
    }
  };
}

const c = volume();

console.log(c.current()); //0
c.up();
console.log(c.current()); //1

 

c에 volume변수를 외부에서 접근할 수있는 방법은 존재하지 않는다. 오직 내부 함수에서만 접근할 수 있는데 이렇듯 클로저를 사용하게 된다면 은닉화를 할 수 있다.  

 

이해가 되었다면 다음 예제도 이해할 수 있다.

 

//HTML
<body>
   <button>1</button>
   <button>2</button>
   <button>3</button>
    <script src="a.js"></script>
 </body>
//js
const el = document.getElementsByTagName("button");
for (var i = 0; i < el.length; i++) {
  el[i].onclick = function() {
    console.log(i);
  };
}

 

위와 같은 경우 어떤 버튼을 클릭해도 3이나 오게 되어있는데 이것은 click콜백의 클로저가 똑같은 i를 공유하고 있기 때문이다. ( window.i = 3  을 공유 )

위의 문제를 해결하는 방법은 여러 가지가 있다. 

 

첫 번째.

es6에서 나온 let을 이용하면 해결할 수 있다. let과 const는 블록 범위 스코프이기 때문에 i의 값을 공유하지 않게 된다.

 

const el = document.getElementsByTagName("button");
for (let i = 0; i < el.length; i++) {
  el[i].onclick = function() {
    console.log(i);
  };
}

 

두 번째.

클로저를 하나 더 만든다. iCallback이라는 함수의 내부 함수가 외부 함수의 인자 i값을 참조하게 되기 때문에 가능하다.

 

function iCallback(i){
    return function(){
        console.log(i);
    }
}
const el = document.getElementsByTagName("button");
for (var i = 0; i < el.length; i++) {
  el[i].onclick =  iCallback(i);
}

 

세 번째는 즉시 실행 함수를 사용하는 것이다.

 

const el = document.getElementsByTagName("button");

for (var i = 0; i < el.length; i++) {
  el[i].onclick = (function(_i) {
   return function(){console.log(_i)}
  })(i)
}

 

let을 사용하는 편이 가장 바람직해 보인다.

'갬발자의 프로그래밍 > Javascript' 카테고리의 다른 글

[Javascript] 프로토타입 언어 : prototype 과 객체 생성  (0) 2021.02.22
유용팁  (0) 2020.03.26
재귀함수  (0) 2020.01.10
배열  (0) 2020.01.09
객체  (0) 2020.01.08

댓글