분류 javascript

더 나은 JavaScript 작성, 파이프 및 작성 기능 구성

컨텐츠 정보

  • 조회 413 (작성일 )

본문

함수형 프로그래밍에 대한 여정을 시작했을 때 나는 그것이 흥미롭고 혼란스럽다고 생각하고 있음을 발견했습니다. 일상 업무에서 유용하다고 생각하는 핵심 개념 중 하나는 함수 구성입니다. 직관적인 특성 덕분에 잘 정립된 코드베이스에서도 도입하기가 어렵지 않습니다.


Compose 


함수 구성에 대해 말할 때 우리는 여러 기능을 함께 연결하여 새로운 기능을 만드는 방법으로 생각할 수 있습니다. 다른 용어로 우리는 문제를 해결하는 것 자체로는 많은 것을 성취하지 못하지만 함께 복잡한 문제를 해결할 수 있는 더 작은 솔루션으로 줄이는 것입니다. 작업.


예를 살펴보겠습니다. 가격에 대해 20% 할인을 계산하려고 한다고 가정해 보겠습니다. 다음과 같은 세 가지 함수를 만들 수 있습니다.


const multiply20 = (price) => price * 20;
const divide100 = (price) => price / 100;
const normalizePrice = (price) => price.toFixed(2);

위의 코드는 정말 간단합니다. 이제 이들을 결합하는 방법을 찾아야 합니다. 보다 전통적인 방법은 함수를 다음 함수의 인수로 넣는 것입니다.


1*Gq3yQWvcjNEpoNzsek3ILg.jpeg 


// result = a(b(c(x)))
const discount = normalizePrice(divide100(multiply20(200))); // 40.00

이런 식으로 내부 함수의 결과는 체인이 끝날 때까지 외부 함수가 인수로 사용합니다.


이제 우리는 기능을 함께 연결할 수 있었고 가독성을 향상시키는 작성 기능을 작성하여 동일한 결과를 얻을 수 있습니다.


const compose = (a, b, c) => (x) => a(b(c(x))); 



1*nPi8K4S8noqPhm-t1IyWHQ.jpeg 


그래서 우리의 코드는 다음과 같습니다:


const discount = compose(normalizePrice, divide100, multiply20);
discount(200.0); //40.00

우리의 compose 함수는 코드를 더 읽기 쉽고 깔끔하게 만들지만 고차 reduceRight 함수를 사용하여 세 개 이상의 함수를 허용하도록 개선할 수 있습니다.


const compose =
  (...fns) =>
  (x) =>
    fns.reduceRight((res, fn) => fn(res), x);


우리가 하는 일은 확산 연산자를 사용하여 인수(함수)를 배열로 변환하고 reduceRight 함수의 누산기의 초기 값으로 사용될 인수 "X"를 취하는 새 함수를 반환하는 것입니다. 우리는 기본적으로 이전 함수의 결과와 함께 오른쪽에서 왼쪽으로 인수로 전달된 모든 함수를 실행하고 있습니다.


따라서 이제 할인에 '$' 접두사를 추가하는 새 함수를 추가하려면 compose arguments 목록에 간단히 추가할 수 있습니다.


const addPrefix = (price) => "$" + String(price); //$ 40.00
const discountWithPrefix = compose(
  addPrefix,
  normalizePrice,
  divide100,
  multiply20
);
discountWithPrefix(200.0); // '$40.00'

Pipe 


1*BePSiFnsUetUm7KN6YQ1Hg.jpeg 


Pipe는 Compose와 똑같은 방식으로 작동합니다. 유일한 차이점은 인수를 오른쪽에서 왼쪽으로 실행하는 대신 왼쪽에서 오른쪽으로 실행한다는 것입니다. 다음과 같이 Pipe 함수를 구현할 수 있습니다.


const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((res, fn) => fn(res), x);

유일한 차이점은 reduceRight가 reduce가되었다는 것입니다. 개인적으로 언뜻 보기에는 직관적이지 않더라도 Compose over Pipe를 선호합니다.


최종 코드는 다음과 같습니다.


const multiply20 = (price) => price * 20;
const divide100 = (price) => price / 100;
const normalizePrice = (price) => price.toFixed(2);
const addPrefix = (price) => "$" + String(price);

const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((res, fn) => fn(res), x);
const compose =
  (...fns) =>
  (x) =>
    fns.reduceRight((res, fn) => fn(res), x);

const discountPipe = pipe(multiply20, divide100, normalizePrice, addPrefix);
const discountCompose = compose(
  addPrefix,
  normalizePrice,
  divide100,
  multiply20
);

discountPipe(200); // '$40.00'
discountCompose(200); // '$40.00'


Ramda 


코드를 작성할 때마다 자체 버전의 Pipe 또는 Compose를 작성할 필요가 없습니다. Ramda와 같은 라이브러리를 사용하고 코드 구현에 집중할 수 있습니다.


출처 : https://itnext.io/write-better-javascript-function-composition-with-pipe-and-compose-93cc39ab16ee