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

← →
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

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

wizjer 29.09.17 в 03:24

0

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

wizjer 29.09.17 в 06:21

0

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

wizjer 29.09.17 в 08:30

0

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

wizjer 29.09.17 в 08:29

0

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

wizjer 29.09.17 в 08:37

0
+4

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

wizjer 29.09.17 в 08:45

0

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

wizjer 29.09.17 в 08:46

0

```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
```

wizjer 29.09.17 в 08:46

0

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

wizjer 29.09.17 в 08:48

0

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

wizjer 29.09.17 в 08:32

0

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

wizjer 29.09.17 в 11:03

0

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

wizjer 29.09.17 в 11:04

0

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

wizjer 29.09.17 в 11:04

0

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

wizjer 29.09.17 в 11:04

0

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

wizjer 29.09.17 в 08:33

0

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

wizjer 29.09.17 в 11:04

0

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

wizjer 29.09.17 в 08:33

0

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

wizjer 29.09.17 в 11:09

0

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

wizjer 29.09.17 в 11:11

0

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

wizjer 29.09.17 в 08:33

0

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

wizjer 30.09.17 в 08:46

0

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

wizjer 30.09.17 в 08:51

0

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

wizjer 30.09.17 в 08:51

0

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

wizjer 30.09.17 в 08:55

0

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

wizjer 30.09.17 в 08:59

0

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

wizjer 30.09.17 в 08:59

0

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

wizjer 30.09.17 в 09:01

0

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

wizjer 30.09.17 в 09:02

0

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

wizjer 29.09.17 в 08:34

0

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

wizjer 30.09.17 в 09:04

0
+1

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

wizjer 30.09.17 в 09:04

0

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

wizjer 30.09.17 в 09:04

0

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

wizjer 30.09.17 в 09:04

0

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

wizjer 30.09.17 в 09:06

0

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

wizjer 30.09.17 в 09:14

0

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

wizjer 02.10.17 в 05:22

0

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

wizjer 02.10.17 в 05:24

0

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

wizjer 02.10.17 в 05:24

0

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

wizjer 02.10.17 в 05:25

0

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

wizjer 02.10.17 в 05:25

0

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

wizjer 02.10.17 в 05:25

0

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

wizjer 02.10.17 в 05:25

0

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

wizjer 02.10.17 в 05:26

0

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

wizjer 02.10.17 в 05:26

0

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

wizjer 02.10.17 в 05:26

0

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

wizjer 02.10.17 в 05:26

0

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

wizjer 02.10.17 в 05:27

0

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

wizjer 02.10.17 в 05:27

0

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

wizjer 02.10.17 в 05:27

0

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

wizjer 02.10.17 в 05:28

0
Минутку...

Следующая страница →