본문 바로가기
Javascript

closure 클로저

by jennyiscoding 2022. 10. 18.

자바스크립트에서 함수는 객체이다. 

클로저는 자바스크립트가 일급객체의 성질을 갖는다는 것(함수를 변수처럼 다룰 수 있다는 것)을 이용해서 만들수 있는 공간임. 내부에 변수가 있을 때 자바스크립트는 그 변수를 클로저 공간에 저장을 한다음 리턴된 함수와 그 변수가 생명을 같이하도록 만든다. 함수를 생성해서 리턴하는 함수를 팩토리함수라고도 부른다. 팩토리 함수 내부에서 생성된 변수들이 있는데 함수가 끝나도 변수들이 살아있게 된다. 그 변수들이 어딨을까? 하는게 클로저의 의미임. 

 

클로저의 예 1 

function createCard(){
  let title="";
  let content="";
  function changeTitle(text){
    title = text;
  }
  function changeContent(text){
    content = text;
  }
  function print(){
    console.log("Title -", title);
    console.log("CONTENT -", content);    
  }
  return {changeTitle, changeContent, print};
}

const card1 = createCard();
card1.changeTitle("생일카드")
card1.changeContent("생일축하해")
card1.print()

 

클로저의 예2 

let rate = 1.05;

function app(){
  let base = 10;

  return function (price){
    return price * rate + base;
  }
}

console.log(app()(50)) //62.5
rate = 1.1;
console.log(app()(1)) //11.1

 

클로저를 왜 사용?

상태를 안전하게 은닉하고 보존시키기 위함. 

 

createCard 함수 본문에 있는 title, content 변수는 외부에서 접근할 수 없습니다.
따라서 changeTitle, changeContent 함수를 통해 수정할 수 있도록 해주었습니다.
값을 읽을 수 있도록 제공하는 함수는 print로 해주었습니다.

그리고 이 모든 함수를 객체로 묶어서 createCard 함수에서 return 합니다.
const myCard = createCard()와 같은 형태로 인스턴스를 만들어서 사용할 수 있습니다.

 

클로저를 이용해서 카운팅 어플 만들기

 

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Template</title>
  </head>
  <body>
    <div id="root">
      <main>
        <h2>Counter App</h2>
        <div class="app">
          <div id="current-count">0</div>
          <button id="increase-button">카운터 증가</button>
          <button id="decrease-button">카운터 감소</button>
        </div>
      </main>
    </div>

      <script src="./index.js"></script>
  </body>
</html>

App.js

import "./app.css";
import Counter from "./Counter";

const App = () => {
  const counter = Counter();

  const increaseButton = document.getElementById("increase-button");
  const decreaseButton = document.getElementById("decrease-button");
  const currentCount = document.getElementById("current-count");

  increaseButton.addEventListener("click", () => {
    counter.increase();
    currentCount.innerHTML = counter.getCount();
  });

  decreaseButton.addEventListener("click", () => {
    counter.decrease();
    currentCount.innerHTML = counter.getCount();
  });
};

export default App;

Counter.js

const Counter = () => {
  // Counter 클로저를 작성하세요.
  let count = 0;
  function getCount() {
    return count;
  }
  function increase() {
    count = count + 1;
  }
  function decrease() {
    count = count - 1;
  }
  return { getCount, increase, decrease };
};

export default Counter;