FP에서 클로저의 활용

jkpark104·2021년 10월 3일
8
post-thumbnail

0. Intro

  • 클로저(Closure)는 화살표 함수와 함께 함수형 프로그래밍(FP)을 구현하는 데에 중요한 역할을 한다.

Q 그렇다면 클로저란 무엇이고 어떤 특성을 갖고 있을까?

1. 클로저

  • 중첩함수가 외부함수의 렉시컬 환경을 참조하고 있을 때, 외부함수의 생명 주기가 끝나도 계속해 중첩함수를 통해 외부함수의 상태(state)를 변경할 수 있는 경우, 중첩함수를 가리켜 클로저(Closure)라고 한다.

  • MDN에 따르면 클로저는 모든 함수가 생성될 때 만들어지지만, 정보 은닉의 목적으로 사용되는 클로저의 개념은 1. 중첩함수를 통해 외부함수의 스코프에 접근할 수 있으면서 2. 생명주기가 외부함수보다 긴 중첩함수를 의미한다.

렉시컬 환경 : 식별자를 등록 관리하는 JS의 자료구조

  • 렉시컬 환경의 참조가 단방향으로 연결돼 있고 이를 통해 중첩함수는 외부함수의 스코프(상위 스코프)를 참조할 수 있다.

2. 클로저의 구현

const counter = (function () {
  let num = 100;
  return {
    increase() {return ++num;},
    decrease() {return --num;}
  };
})(); // 즉시 실행 함수의 호출로 외부 함수의 생명 주기가 종료되고 클로저가 생성됨
      // 중첩함수 increase|decrease를 통해 외부함수의 식별자 num의 상태 변경이 가능함
console.log(counter.increase()); // 101
console.log(counter.decrease()); // 100
console.log(counter.num); // undefined, 전역 코드에서 식별자 num을 참조할 수 없음
  1. 클로저의 외부함수 식별자 num을 가리켜 자유변수라고 한다.
  2. 클로저(Closure)는 자유변수에 대해 닫혀(Closed)있다.

클로저를 통해 사용자는 상태(state)를 안전하게 접근하고 변경할 수 있다.

3. FP에서 클로저의 활용

  • 2. 클로저의 구현 처럼 클로저 패턴은 OOP에서 상태 은닉과 객체 간 결합도(Coupling)를 낮추는데 사용된다.
  • 또한, 클로저는 화살표 함수와 함께 함수형 프로그래밍(FP)에서도 중요한 역할을 한다.

    함수형 프로그래밍

    • 부수 효과가 없는 순수 함수들을 이용해 프로그램을 선언적으로 기술하는 프로그래밍 패러다임
    • 조건문 | 반복문 | 부수 효과 등을 제거해 프로그램의 복잡성을 낮추고 코드의 유지 보수성을 높인다.

예제 (1)

const sayHi = name => console.log(`Hi ${name}`);
const sayGoodBye = name => console.log(`Goodbye! ${name}`);

const say = conversation => name => conversation(name);

say(sayHi)('Park'); // Hi! Park
say(sayHi)('Lee'); // Hi! Lee
say(sayGoodBye)('Kim'); // Goodbye! Kim
  1. say라는 함수는 매개변수(conversation)를 받아 클로저를 생성한다.
  2. 클로저는 매개변수(name)를 받아 최종적으로 말(say)하는 동작을 수행한다. eg. Hi! Park

예제 (2)

const items = [
  { name: 'Park', hobby: 'Hiking' },
  { name: 'Lee', hobby: 'Watching a movie' },
  { name: 'Kim', hobby: 'Basketball' }
];

// 1. 보조함수 where
const where = (key, value) => item => item[key] === value;
// 2. 보조함수 filter
const filter = where => items => items.filter(where);
// 3. 보조함수 applier
const applier = (key, value) => item => {
  item[key] = value;
};
// 4.보조함수 map
const map = fnMap => targetItem => targetItem.map(fnMap);

// 5. 합성함수 getNewItems
const getNewItems = (items, applyFnc, whereFnc) => {
  const newItems = items.map(item => ({ ...item }));
  map(applyFnc)(filter(whereFnc)(newItems));
  return newItems;
};

const newItems = getNewItems(
  items,
  applier('hobby', 'Soccer'),
  where('name', 'Park')
);

console.log(items);
// [
//   { name: 'Park', hobby: 'Hiking' },
//   { name: 'Lee', hobby: 'Watching a movie' },
//   { name: 'Kim', hobby: 'Basketball' }
// ]
console.log(newItems);
// [
// { name: 'Park', hobby: 'Soccer' },
// { name: 'Lee', hobby: 'Watching a movie' },
// { name: 'Kim', hobby: 'Basketball' }
// ]
  1. 특정 key | value를 기억하는 클로저를 만들어 key에 대해 일치 여부를 반환하는 보조함수 where
  2. 보조함수 where를 조건으로 하는 클로저를 만들어 수정할 객체를 필터링 하는 보조함수 filter
  3. 특정 key, value를 기억하는 클로저를 만들어 특정 프로퍼티 key의 value를 변경하는 보조함수 applier
  4. where 조건에 만족하는 객체의 요소를 받아 applier 함수를 적용하는 매핑 함수의 역할을 하는 보조함수 map
  5. getNewItems는 보조함수들의 도움을 받아 새로운 객체 newItems를 반환한다.

함수형 프로그래밍(FP)에서 클로저와 화살표 함수는
1. 함수의 합성
2. 함수의 가독성
3. 부수 효과 제거에 중요한 역할을 한다.

4. 결론

  • 클로저 패턴은 외부에서 참조할 수 없고 특정 함수를 통해 접근 가능한 중첩함수 클로저를 만들어 낸다.
  • 클로저를 통해 OOP에서 자유 변수에 대해 외부에서 접근할 수 없게 만들어 객체 간 결합도를 낮출 수 있다.
  • 클로저와 화살표 함수를 활용해 FP에서 함수를 효율적으로 합성하고 부수 효과를 낮출 수 있다.

5. 참고

0개의 댓글