Композиция функций с функцией высшего порядка в JavaScript

Dec 04 2022
В этой статье давайте попробуем понять, как мы можем создать сложную функциональность, составив более мелкие функции в JavaScript. ЕСТЬ, СОН, КОД — Вложенный подход Предположим, что мы хотим выполнить действие «ЕСТЬ, СОН, КОД», и повторим это снова.
Фото Келли Сиккема на Unsplash

В этой статье давайте попробуем понять, как мы можем создать сложную функциональность, составив более мелкие функции в JavaScript.

ЕСТЬ, СОН, КОД — Вложенный подход

Давайте предположим, что мы хотим выполнить действие «Ешь, Сплю, Кодируй» и повторяем это снова. Вот подход, как мы могли бы это сделать.

const activity = (str) => str.toUpperCase();
const sleep = (str) => `${str} SLEEP`;
const code = (str) => `${str} CODE`;
const repeat = (str) => `${str} | ${str}`;

// EAT SLEEP CODE | EAT SLEEP CODE
console.log(
  repeat(code(sleep(activity('eat'))))
  );

ЕСТЬ, СОН, КОД — композиция высшего порядка

Мы посмотрим, как мы могли бы улучшить это, используя функцию более высокого порядка, которая создала бы для нас композицию.

const activity = (str) => str.toUpperCase();
const sleep = (str) => `${str} SLEEP`;
const code = (str) => `${str} CODE`;
const repeat = (str) => `${str} | ${str}`;

// Higher order function that accepts any number of functions as arguments
const compose = (...fns) => x => fns.reduce((acc, fn)=> fn(acc),x);
const myRoutine = compose(activity, sleep, code, repeat);

// EAT SLEEP CODE | EAT SLEEP CODE
console.log(myRoutine('eat'));

  • Метод compose может принимать несколько функций в качестве аргументов с использованием оператора rest.
  • Затем он возвращает функцию, ожидающую своего начального значения.
  • Внутри этой возвращенной функции мы можем получить доступ к массиву функций, которые были переданы в качестве аргумента (закрытие).
  • Порядок функции идет слева направо. Поэтому мы будем использовать метод сокращения, который принимает аккумулятор и текущее значение, которое является функцией. Это вернет результат накопленного значения текущей функции.
  • Второй аргумент редукции — это наше начальное значение x.
  • Таким образом, мы можем, наконец, создать нашу рутину, составив все наши действия. Подпрограмму следует вызывать, передавая аргумент первой функции.

Вот разбивка функции составления для большей ясности.


// Arrow variant
const compose = (...fns) => x => fns.reduce((acc, fn)=> fn(acc),x);

// Non arrow variant
function compose(...fns) {
  return function (x) {
    return fns.reduce((acc, fn) => fn(acc), x);
  };
}

Этот подход имеет следующие преимущества:

  • Помогает уменьшить громоздкость, вызванную вложением нескольких функций.
  • Читабельный и масштабируемый