До сих пор мы делали некоторые чистые служебные функции (например, карту, фильтр).

Сегодня мы сделаем три функции: «уменьшить» и «карри». Они будут хорошими инструментами на следующем этапе - конвейерной обработке.

1. Уменьшить

Функция Reduce принимает коллекцию, итерацию и аккумулятор (необязательно, начальное значение). И он возвращает только один накопленный результат выполнения каждого элемента с collection по iteratee.

Аккумулятор, это 3-й параметр, необязательное значение. Если нет, первый элемент коллекции будет начальным значением.

Итеративным называется каждый элемент коллекции. Он берет результат предыдущего итератора и текущий элемент и возвращает новый результат.

const usersMock = [
  { id: 1, name: 'user1', age: 11 },
  { id: 2, name: 'user2', age: 21 },
  { id: 3, name: 'user3', age: 23 },
  { id: 4, name: 'user4', age: 11 },
  { id: 5, name: 'user5', age: 37 },
  { id: 6, name: 'user6', age: 23 },
];

test('reduce', () => {
  expect(reduce(usersMock, (sum, user) => sum + user.age, 0)).toBe(126);
});

В этом коде reduce возвращает сумму возраста пользователей. Функция iteratee получает начальное значение 0 и добавляет возраст первого пользователя. Если первый цикл завершен, второй цикл начинается с первого результата и второго элемента. Повторяйте этот процесс до конца. Тогда как мы можем реализовать «сокращение»? Он также просматривает коллекцию, поэтому давайте воспользуемся "each".

const each = require('../each');
function reduce(collection, iteratee, accumulator) {
  let iterable = collection;
  let result = accumulator;
  if (arguments.length == 2) {
    result = collection[0];
    iterable = Array.prototype.slice.call(collection, 1);
  }
  each(iterable, (value) => {
    result = iteratee(result, value);
  });
  return result;
}
module.exports = reduce;

Берем 2 или 3 аргумента. Если их 2, мы используем первый элемент в качестве третьего аргумента. И, пройдя цикл «each», установите результат равным возвращаемому значению итерации.

Карта, Фильтр, Уменьшение

Вся большая часть обработки данных состоит из этих трех функций: сопоставления, фильтрации и сокращения.

«Карта» однозначно сопоставляет данные. Он изменяет каждое значение данных, поэтому возвращает коллекцию той же длины.

«Фильтр» фильтрует данные в соответствии с условиями. Нет никаких изменений в каждом значении. Но длину данных можно изменить.

Наконец, «уменьшить» возвращает только одно значение. Он объединяет все элементы, чтобы создать один результат.

2. Карри, карри-право

Карри - очень интересная функция. Он принимает функцию и возвращает новую функцию. Любопытно, что он заставляет функцию ввода принимать ввод последовательно!

Давайте сначала посмотрим на код.

function curry(fn) {
  return (first, ...args) => args.length
    ? fn(first, ...args)
    : (...args2) => fn(first, ...args2);
}
module.exports = curry;

«Карри» возвращает новую функцию. Если новая функция принимает только один входной параметр, она возвращает функцию с первым набором входных данных. Так что мы можем использовать его, когда нам это нужно. Как мы можем это использовать? Подумайте об этом коде.

test('curry', () => {
  const curryReduce = curry(reduce);
  const numbersReduce = curryReduce([1, 2, 3, 4, 5]);
  const sumTotal = numbersReduce((sum, value) => sum + value, 0 );
  const sumOdds = numbersReduce((sum, value) => value % 2 ? sum + value : sum, 0 );
  expect(sumTotal).toBe(15);
  expect(sumOdds).toBe(9);
});

Мы назвали «карри», указав на входе «уменьшить». «Reduce» принимает только 2 или 3 аргумента, но curryReduce теперь может принимать только первый аргумент. В результате была создана функция numbersReduce. можем поставить любой итератор и аккумулятор!

Мы также можем сделать функцию «каррир». Это заставляет функцию ввода сначала принимать только второй аргумент.

function curryr(fn) {
  return (first, ...args) => args.length
    ? fn(first, ...args)
    : (innerFirst, ...args2) => fn(innerFirst, first, ...args2);
}
module.exports = curryr;

Таким образом, в случае «сокращения» мы можем поставить на первое место итеративную логику.

test('curryr', () => {
  const curryrReduce = curryr(reduce);
  const sumReduce = curryrReduce((sum, value) => sum + value);
  const sumTotal = sumReduce([1, 2, 3, 4, 5]);
  expect(sumTotal).toBe(15);
});

Как вы увидите из будущего, мы обычно сначала ставим логику итеративного элемента, а затем вводим данные таким же образом.
Теперь, когда все ингредиенты готовы, давайте в следующий раз приступим к конвейерной обработке с использованием функций!

Исходный код Github