클로저

Verba volant, scripta manent·2020년 12월 4일
1

JavaScript

목록 보기
7/20
post-thumbnail

Closure

1. 클로저(Closure)란?

외부 함수의 변수에 접근할 수 있는 내부 함수 또는 이러한 작동 원리를 일컫는다.
함수와 함수가 선언된 어휘적 환경의 조합

ex)
function outerFn() {
let outerVar = 'outer';
console.log(outerVar);

function innerFn() {
let innerVar = 'inner';
console.log(innerVar);
}
return innerFn;
}

let globalVar = 'global';
let innerFn = outerFn();
innerFn();

라고 하면 클로저함수는 노란색이다.

2. 클로저 함수의 특징

클로저 함수 안에서는 지역 변수(innerVar), 외부 함수의 변수(outerVar), 전역 변수(globalVar)의 접근이 전부 가능하다.

3. 클로저 입문

(문제1) 다음 코드에서 inner 함수에서 접근할 수 있는 Scope는 총 몇개인가?

function outerFn() {
  let outerVar = 'outer';
  console.log(outerVar);
  
  function innerFn() {
    let innerVar = 'inner';
    console.log(innerVar);
  }
}

let globalVar = 'global';
outerFn();

답은 총 3개이다.

1 .

  function innerFn() {
    let innerVar = 'inner';
    console.log(innerVar);
  }

2 .

function outerFn() {
  let outerVar = 'outer';
  console.log(outerVar);
  
  function innerFn() {
    let innerVar = 'inner';
    console.log(innerVar);
  }
}

3 .

function outerFn() {
  let outerVar = 'outer';
  console.log(outerVar);
  
  function innerFn() {
    let innerVar = 'inner';
    console.log(innerVar);
  }
}

let globalVar = 'global';
outerFn();

scope는 여기서부터 시작한다.

(문제2)
만약

function outerFn() {
let outerVar = 'outer';
console.log(outerVar);

function innerFn() {
let innerVar = 'inner';
console.log(innerVar);
}
return innerFn;
}

outerFn();

처럼 return innerFn;이 추가된다면 outerFn() 실행결과는 어떻게 되는가??

이 경우 함수도 리턴할 수 있다.

그럼 다음 문제도 풀어보자.
(문제3)

function outerFn() {
  let outerVar = 'outer';
  console.log(outerVar);
  
  function innerFn() {
    let innerVar = 'inner';
    console.log(innerVar);
  }
  return innerFn;
}

라고 했을 때 다음의 경우 각각 콘솔에 어떻게 찍힐까?
outerFn()(); // ①
let innerFn = outerFn(); // ②
innerFn(); // ③

4. 유용한 클로저 예제

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

function adder(x) {
  return function(y) {
    return x + y;
  }
}

이라고 하면 
adder(2)(3); // 5 : 2 + 3

let add100 = adder(100); 이라고하면
add100(2); // 102 : 100 + 2
add100(10); // 110 : 100 + 10

let add5 = adder(5); 라고 하면
add5(2); // 7 : 5 + 2

x의 값을 고정해놓고 재사용할 수 있다!

2) 외부 함수의 변수가 저장되어 마치 템플릿 함수와 같이 사용 가능

function htmlMaker(tag) {
  let startTag = '<' + tag + '>';
  let endTag = '</' + tag + '>';
  return function(content) {
    return startTag + content + endTag;
   }
 }
 
 let divMaker = htmlMaker('div');
 divMaker('code'); // <div>code</div>
 divMaker('states'); // <div>states</div>
 
 let h1Maker = htmlMaker('h1');
 h1Maker('Headline'); // <h1>Headline</h1>

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

function makeCounter() {
  let privateCounter = 0;
  
  return {
    increment: function() {
      privateCounter++;
    },
    decrement: function() {
      privateCounter--;
    },
    getValue: function() {
      return privateCounter;
    }
  }
}

이라고 하면,

let counter1 = makeCounter();
counter1.increment();
counter1.increment();
counter1.getValue();

let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue();

일 경우 counter1.getValue();counter2.getValue();의 값은 무엇인가?

답은

let counter1 = makeCounter();
counter1.increment();
counter1.increment();
counter1.getValue(); // 2

let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue(); // 1

이다.

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

profile
말은 사라지지만 기록은 남는다

0개의 댓글