JavaScript - Closure

LANA·2020년 4월 6일
0

JavaScript

목록 보기
9/21
post-thumbnail

scope의 연장으로 생각하면 쉬움.
array method, callback을 배울 때 함수를 파라미터로 받을 수 있는 것을 배웠지만, 여기선 함수를 리턴할 수 있단 것도 알 수 있다.

function outerFn() {
  let outerVar = 'outer';
  console.log(outerVar); // 이로 인해 콘솔창에 outerVar의 값이 찍히고,
  
  function innerFn() {
    let innerVar = 'inner';
    console.log(innerVar);
  }
  return innerFn; // 아직 실행되지 않은 함수(innerFn)가 리턴됨.
}
outerFn(); // 출력 1.outer   2.innerFn(실행되지 않은채로)

outerFn()(); // 출력 1.outer   2.inner (innerFn에 ()가 붙어, innerFn이 실행됨)

let innerFn = outerFn(); //출력 outer; innerFn이 실행되지 않은채로 return.
//이 상태에서 콘솔창에 innerFn 찍으면 innerFn에 대한 설명을 볼 수 있음.
innerFn(); //출력 inner; 위에서 outerFn()돌린 후 innerFn에 ()를 찍으니까.

Closure(클로저)
외부 함수의 변수에 접근할 수 있는 내부 함수.
또는, 이러한 작동 원리를 일컫는 용어.
(위의 innerFn가 클로저 함수.)

  • 클로저 함수 안에서는 아래의 접근이 모두 가능함.
    • 지역 변수(innerVar)
    • 외부 함수의 변수(outerVar)
    • 전역 변수(globalVar)

유용한 클로저 예제

커링
함수 하나가 n개의 인자를 받는 대신, n개의 함수를 만들어 각각 인자를 받게 하는 방법.

  • 유용한 이유
    • x의 값을 고정해놓고 재사용할 수 있다.
    • 외부 함수의 변수가 저장되어 마치 템플릿 함수와 같이 사용 가능(특히 html)
    • 참조: 커링에 대해 정리한 글

예제1)

function adder(x) {
  return function(y) {
    return x + y;
  }
}
adder(2)(3); //5

예제2)

let add100 = adder(100);
add100(2); // 102
add100(10); //110

let add5 = adder(5)
add5(2); //7

예제3) html에서 ~Maker 만들 경우

function htmlMaker(tag) {
  let startTag = '<' + tag + '>'
  let endTag = '</' + tag + '>'
  return function(content) {
    return startTag + content + endTag;
  }
}

let divMaker = htmlMaker('div')
divMaker('안녕하세요') // "<div>안녕하세요</div>"

let spanMaker = htmlMaker('span')
spanMaker('오오') // "<span>오오</span>"

클로저 모듈 패턴
변수를 스코프 안쪽에 가두어 함수 밖으로 노출시키지 않는 방법.

  • 유용한 이유
    • x의 값을 고정해놓고 재사용할 수 있다.
    • 외부 함수의 변수가 저장되어 마치 템플릿 함수와 같이 사용 가능(특히 html)
function makeCounter() {
  let privateCounter = 0;
  
  return{
    increment: function() {
      privateCounter++;
    },
    decrement: function() {
      privateCounter--;
    },
    getValue: function() {
      return privateCounter;
    }
  }
}

두 카운터에 각기 다른 privateCounter를 다루면서,
privateCounter를 밖으로 노출시키지 않는다.

let counter 1 = makeCounter();
counter1.increment();
counter1.increment();
counter1.getValue(); //2
>
let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue(); //1
profile
Let's code like chord !

0개의 댓글