나의 개발일지

클로저(Closure)란 | 사용 예시 및 클로저 사용 이유 본문

JavaScript

클로저(Closure)란 | 사용 예시 및 클로저 사용 이유

heew0n 2024. 4. 28. 00:35

 

 

클로저란 함수와 함수가 선언되었을 때의 렉시컬 환경의 조합

클로저란, 자신이 선언된 당시의 환경을 기억하는 함수
클로저란, 생명 주기가 끝난 외부 함수의 변수에 접근할 수 있는 내부 함수

 

function closure() {
  var name = heewon"; // name은 클로저에 의해 생성된 지역 변수
  function displayName() {
    // displayName() 은 내부 함수이며, 클로저다.
    console.log(name); // 부모 함수에서 선언된 변수를 사용한다.
  }
  displayName();
}
closure();

 

clousure()은 지역 변수 name과 함수 displayName()을 생성

displayName()은 clousure() 안에 정의된 내부함수이며 clousure() 함수 본문에서만 사용이 가능하다.

여기서 주의할 점은 displayName() 내부엔 자신만의 지역 변수가 없다는 것

하지만 내부 함수에서 외부 함수의 변수의 접근할 수 있기 때문에, displayName() 역시 부모함수 clousure()에서 선언된 name에 접근할 수 있는 것이다.

 

 

 

 

클로저를 활용한 카운터 구현 예시

function createCounter() {
  let count = 0;

  return {
    increment: function () {
      count++;
      return count;
    }
  };
}

// 사용 예시
const counter = createCounter();
console.log(counter.increment()); // 출력: 1
console.log(counter.increment()); // 출력: 2

 

 

변수 count는 createCounter 함수가 호출되면 0으로 초기화가 된다.

그리고 createCounter()는 객체를 반환하는데, 이 객체에는 increment라는 메서드가 포함되고 있다

increment는 count를 증가시키고 그 값을 반환한다.

내부 함수에서 메서드가 실행되지만 지역 변수에 접근이 가능하기 때문에 카운터를 증가시키고, 값이 누적될 수 있다

 

 

 

클로저 사용 이유

 

1. 상태 유지
현재 상태를 기억하고 변경된 최신 상태를 유지할 수 있다.

function createCart() {
  let items = [];

  function addItem(item) {
    items.push(item);
    return items.length;
  }

  function removeItem(item) {
    const index = items.indexOf(item);
    if (index !== -1) {
      items.splice(index, 1);
    }
    return items.length;
  }

  function getItems() {
    return items.slice();
  }

  function getItemCount() {
    return items.length;
  }

  return {
    addItem,
    removeItem,
    getItems,
    getItemCount
  };
}

// 사용 예시
const cart = createCart();
cart.addItem('사과');
cart.addItem('바나나');
cart.addItem('오렌지');
console.log(cart.getItemCount()); // 3
console.log(cart.getItems()); // ['사과', '바나나', '오렌지']
cart.removeItem('바나나');
console.log(cart.getItemCount()); // 2
console.log(cart.getItems()); // ['사과', '오렌지']

 

createCart() --> 장바구니 기능 구현

내부에 items 배열을 유지하고, 이 배열을 조작하는 메서드들을 반환한다.

 

addItem: 새로운 항목을 장바구니에 추가하고 현재 장바구니 크기를 반환
removeItem: 특정 항목을 장바구니에서 제거하고 현재 장바구니 크기를 반환
getItems: 현재 장바구니의 항목들을 복사하여 반환
getItemCount: 현재 장바구니의 항목 개수를 반환

 

이렇게 클로저를 사용하면 items 배열의 상태를 외부에 노출하지 않고도 장바구니 기능을 구현할 수 있다. 각 메서드는 items 배열에 접근할 수 있는 클로저 함수이기 때문에 상태를 유지할 수 있는 것이다.

 

 

2. 정보 은닉
변수 값을 은닉할 수 있습니다. 클래스 기반 언어의 private 키워드를 흉내낼 수 있다.


3. 전역 변수 사용 억제
전역 변수를 통해서 공유할 변수를 작성하고는 하지만, 전역 변수는 의도치 않게 값이 변경될 위험이 있다. 클로저를 사용하면 변수를 공유하는 특성은 유지하되 데이터를 은닉화할 수 있기 때문에, 전역 변수를 대체하여 안전한 코드를 작성할 수 있다.