Map, Filter, Reduce в JavaScript

27.01.2020

Большинство методов объекта Array, которые мы рассмотрели, являются мутабельными. Они изменяют существующий массив. Существуют так называемые иммутабельные методы, которые возвращают совершенно новую копию массива. В данной статье мы рассмотрим три иммутабельных метода: map, filter, reduce.

.map()

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

let numbers = [1,2,3,4,5];
console.log(numbers.map(n => n*n)); // -> [1, 4, 9, 16, 25]

Рассмотрим пользовательскую функцию, она может принимать до трех аргументов. (value: T, index: number, array: T[])

  1. value - элемент массива,
  2. index - позиция элемента в массиве
  3. array - оригинальный массив Метод map может принимать дополнительный параметр контекст выполнения this для пользовательской функции.

.filter()

Как видно из названия метод занимается фильтрацией массива. На входе мы должны указать функцию-предикат которая будет решать пропускать элемент или нет. На выходе мы получаем новый массив элементов, которые удовлетворяют нашему фильтру. Проиллюстрируем на примере.

let numbers = [1,2,3,4,5,6];
numbers.filter(i => i % 2 === 0); // -> [2, 4, 6]

Пользовательская функция имеет точно такую же сигнатуру как и в методе map . Метод filter может принимать дополнительный параметр контекст выполнения this для пользовательской функции. Если никто не прошел проверку, то функция filter вернет пустой массив.

.reduce()

Функция reduce устроена совершенно по другому в отличие от map и filter. На входе она получает массив элементов, а на выходе значение любого возможного типа, необязательно массив. reduce принимает пользовательскую функцию и необязательный объект, который является начальным значением, если его не указать то будет использоваться первый элемент массива. previousValue, currentValue, currentIndex: number, array: [])

  1. previousValue - значение аккумулятора, промежуточное значение,
  2. currentValue - текущий элемент массива
  3. index - позиция элемента в массиве
  4. array - оригинальный массив. При работе функции reduce следует понимать, что результат вызова каждой пользовательской функции над элементом передается в следующий вызов. Промежуточное значение называется аккумулятор. Аккумулятор может быть любого типа, начальное значение может быть взято из второго аргумента функции reduce, либо как первый элемент массива, Покажем работу функции на примере,
let numbers = [1, 2, 3, 4, 5];
numbers.reduce( (acc, val) => acc + val); // -> 15

Комбинирование методов

Допустим у нас есть задача посчитать суммарную расходы по категории - “salary”. На входе мы имеем следующие данные

const outcome = [
    { amount: 1000, category: 'tax'},
    { amount: 2000, category: 'salary'},
    { amount: 2000, category: 'tax'},
    { amount: 3000, category: 'salary'},
    { amount: 2540, category: 'salary'},
    { amount: 230,  category: 'salary'},
    { amount: 2200, category: 'salary'},
];

Реализуем алгоритм с помощью только что представленных методов:

outcome
    .filter( ({category}) => category === 'salary' )
    .map( item => item.amount )
    .reduce( (acc, val) => acc + val );
// -> 9970

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

Как только вы почувствуете что разобрались со всеми функциями объекта Array, попробуйте посмотреть в сторону библиотеки lodash. В ней представлено огромное множество функций по обработке массивов, скорее всего вам даже не придется ничего изобретать нового, просто грамотно скомпоновать уже существующие функции.

#jsbook#javascript

Еженедельная рассылка новостей

Глобальный объект в JavaScript

Редакторы кода