Готовый перевод Modern JS Cheatsheet / Памятка по современному JavaScript: Методы массивов - map / filter / reduce

### Методы массивов - map / filter / reduce

*Map*, *filter* и *reduce* это методы массивов, пришедшие из парадигмы [*функционального программирования*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0).

Перечислю их:

- **Array.prototype.map()** берет массив, делает что-то с его элементами и возвращается массив трансформированных элементов.
- **Array.prototype.filter()** берёт массив, просматривает каждый элемент и решает, убрать его или оставить, и возвращает массив оставшихся значений.
- **Array.prototype.reduce()** берёт массив и вычисляет на основе элементов какое-то единое значение, которое и возращает

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

Вооружившись этими тремя методами, вы можете обойтись без использования *for* и *forEach* в большинстве ситуаций. Когда в следующий раз соберётесь запустить цикл *for*, попробуйте решить задачу с помощью *map*, *filter* и *reduce*. Поначалу это будет трудно, потому что вам придётся научиться мыслить по-другому, но, разобравшись один раз, вы сможете применять эти методы без особых усилий.

#### Пример кода

```js
const numbers = [0, 1, 2, 3, 4, 5, 6];
const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12]
const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6]
const sum = numbers.reduce((prev, next) => prev + next, 0); // 21
```

Давайте посчитаем сумму баллов всех студентов, которые набрали больше 10 баллов, используя *map*, *filter* и *reduce*:

```js
const students = [
{ name: "Коля", grade: 10 },
{ name: "Ваня", grade: 15 },
{ name: "Юля", grade: 19 },
{ name: "Наташа", grade: 9 },
];

const aboveTenSum = students
.map(student => student.grade) // создаём массив оценок из массива студентов с помощью метода map
.filter(grade => grade >= 10) // выбираем только оценки выше 10 при помощи метода filter
.reduce((prev, next) => prev + next, 0); // суммируем все оценки выше 10 друг с другом

console.log(aboveTenSum) // 44 -- 10 (Коля) + 15 (Ваня) + 19 (Юля), оценка Наташи меньше 10 и была проигнорирована
```

#### Объяснение

Давайте использовать в качестве примера следующий массив:

```js
const numbers = [0, 1, 2, 3, 4, 5, 6];
```

##### Array.prototype.map()

```js
const doubledNumbers = numbers.map(function(n) {
return n * 2;
});
console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12]

Что же здесь происходит? Мы применяем к массиву *numbers* метод .map, который взаимодействует с каждым элементом массива и передаёт его в нашу функцию. Цель функции произвести расчёт и вернуть новое значение, чтобы map мог подставить его вместо переданного в функцию.

Давайте даже вынесем функцию из массива, чтобы было понятнее, что происходит:

```js
const doubleN = function(n) { return n * 2; };
const doubledNumbers = numbers.map(doubleN);
console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12]
```

```numbers.map(doubleN)``` создаёт ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]``` что равняется ```[0, 2, 4, 6, 8, 10, 12]```.

> **Примечание:** Если вы не хотите возвращать новый массив и просто хотите перебрать массив, совершая некоторые действия, то, возможно, вы захотите использовать просто for / forEach вместо метода map.

##### Array.prototype.filter()

```js
const evenNumbers = numbers.filter(function(n) {
return n % 2 === 0; // истинно, если "n" чётное, ложно если "n" нечетное
});
console.log(evenNumbers); // [0, 2, 4, 6]
```

Мы применяем .filter к массиву *numbers*, filter взаимодействует с каждым элементом массива и передаёт его в нашу функцию. Функция возвращает булево значение, что определяет, будет ли элемент сохранён в массиве. Затем filter возвращает массив отфильтрованных значений.

##### Array.prototype.reduce()

Цель метода reduce заключается в том, чтобы вычислить на основе массива какое-то одно значение. Какие именно вычисления метод произведет с элементами зависит только от вас.

```js
const sum = numbers.reduce(
function(acc, n) {
return acc + n;
},
0 // значение аккумулирующей переменной на первом шаге цикла
);

console.log(sum) //21
```

Также как методы .map и .filter, метод .reduce применяется к массиву и в качестве первого параметра принимает функцию.

На этот раз, впрочем, кое-что изменилось:

- .reduce принимает два параметра

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

Второй параметр это значение аккумулирующей переменной (*acc* в нашем случае) на первом шаге цикла (чтобы разобраться, читайте далее)

- Параметры функции

Функция, которую вы передаёте в качестве первого параметра метода .reduce принимает два параметра. Первый параметр это аккумулирующая переменная (*acc* в нашем примере), второй параметр — текущий элемент.

Аккумулирующая переменная равна значению, возвращённому нашей функцией на **предыдущем** шаге цикла. В самом начале каждого цикла *acc* равна значению, которое вы передали в качестве второго параметра .reduce.

###### На первом шаге

```acc = 0``` потому что мы передали 0 в качестве второго параметра метода reduce

```n = 0``` это первый элемент массива *number*

Функция возвращает *acc* + *n* --> 0 + 0 --> 0

###### На втором шаге

```acc = 0``` потому что это значение функция вернула на предыдущем шаге

```n = 1``` это второй элемент массива *number*

Функция возвращает *acc* + *n* --> 0 + 1 --> 1

###### На третьем шаге

```acc = 1``` потому что это значение функция вернула на предыдущем шаге

```n = 2``` это третий элемент массива *number*

Функция возвращает *acc* + *n* --> 1 + 2 --> 3

###### На четвертом шаге

```acc = 3``` потому что это значение функция вернула на предыдущем шаге

```n = 3``` это четвёртый элемент массива *number*

Функция возвращает *acc* + *n* --> 3 + 3 --> 6

###### На последнем шаге

```acc = 15``` потому что это значение функция вернула на предыдущем шаге

```n = 6``` последний элемент массива *number*

Функция возвращает *acc* + *n* --> 15 + 6 --> 21

Поскольку это был последний шаг, **.reduce** возвращает 21.

#### Внешние ресурсы

- [Понимание методов map / filter / reduce в JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464)

Переведено на Нотабеноиде
http://notabenoid.org/book/70916/381878

Переводчики: wizjer

Настройки

Готово:

100.00% КП = 1.0