Перебирающие методы массива

1. Введение

В JavaScript есть методы массивов. пришедшие из функциональных языков. Они получают исходный массив, создают новый пустой массив и заполняют его, применяя к копии значения каждого элемента указанную callback-функцию.

Все функциональные методы массивов имеют схожий синтаксис. Исходный массив array, вызов метода method и callback-функция callback в качестве аргумента метода.

array.method(callback[currentValue, index, array])
Copy

В большинстве методов, аргументами callback-функции являются значение элемента currentValue (первый параметр), позиция элемента index (второй параметр) и сам исходный массив array (третий параметр).

array.method((item, idx, arr) => {
  // логика которая будет применяться на каждой итерации
});
Copy

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

array.method(item => {
  // логика которая будет применяться на каждой итерации
});
Copy

2. Array.prototype.forEach()

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

  • Перебирает

  • Может изменять

  • Не возвращает

Код более декларативный, читабельный, поддерживаемый. Поэтому дальнейшее использование цикла for при выполнении домашних работ не рекомендуется. Единственным местом, где все еще необходимо использовать цикл for, это задача с прерыванием выполнения цикла, forEach прервать инструкцией break нельзя.

3. Array.prototype.map()

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

  • Используется для трансформации массива

  • Перебирает

  • Не изменяет

  • Возвращает коллекцию

Используем map чтобы пройти по базе данных users и получить массив всех имен пользователей.

Array.map на MDN

4. Array.prototype.filter()

Применяет callback-функцию к каждому элементу исходного массива и если результат ее выполнения имеет значение true, то копирует значение из исходного массива в новый массив. Исходный и новый массив могут иметь разную длину. Не мутирует исходный массив. Всегда возвращает массив, даже если в нем всего 1 элемент. Если ничего не найдено, вернет пустой массив. Используется, когда необходимо найти более одного элемента в коллекции.

  • Используется для фильтрации массива

  • Перебирает

  • Не изменяет

  • Возвращает коллекцию

Используем filter, чтобы пройти по базе данных users и выбрать активных и неактивных пользователей по значению свойства isActive.

Array.filter на MDN

5. Array.prototype.find()

Что делать, если нам нужно найти уникальный id пользователя среди 30000 объектов, а среди 300000?

Первое, что вы хотели бы сделать - это вызвать filter, пройти по коллекции и вернуть только того пользователя, id которого совпадет. Это работает, но какой ценой? Представьте, что нужный нам объект пользователя стоит под индексом 2 в массиве. Какой смысл фильтровать все остальное? Мы теряем производительность из-за лишних операций.

Для таких случаев есть метод find, который будет искать до первого совпадения, после чего прервет свое выполнение.

Применяет callback-функцию к каждому элементу исходного массива и если результат ее выполнения имеет значение true, то возвращает этот элемент и завершает свое выполнение. Если ничего не найдено, вернет undefined.

  • Используется для поиска уникального элемента массива

  • Перебирает

  • Не изменяет

  • Возвращает элемент

Используем find, чтобы пройти по базе данных users и найти пользователя по идентификатору id. Идентификаторы всегда уникальны.

Array.find на MDN

6. Array.prototype.every() и Array.prototype.some()

Метод every проверяет, прошли ли все элементы массива тест, предоставляемый callback-функцией. Возвращает true, если вызов callback-функции вернет true для каждого элемента в array.

Метод some проверяет, проходит ли по крайней мере один элемент в массиве тест, предоставляемый callback-функцией. Возвращает true, если вызов callback-функции вернет true хотя бы для одного элемента в array.

  • Перебирает

  • Не изменяет

  • Возвращает true или false

Давайте еще пример. Есть массив объектов фруктов, необходимо узнать все ли фрукты есть в наличии и есть ли в наличии хоть какие-то фрукты более 0 штук.

7. Array.prototype.reduce()

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

  • Перебирает

  • Не изменяет

  • Возвращает что угодно

  • previousValue — промежуточный результат (аккумулятор)

  • currentItem — текущий элемент массива

  • index — индекс текущего элемента массива

  • array — оригинальный массив

Легко представить ее работу на примере подсчета суммы значений элементов массива. Если в качестве callback-функции задать сложение, то reduce вернет сумму всех значений массива.

Работает это так:

  • Функция reduce создаст новую переменную, называемую аккумулятор. Затем присвоит аккумулятору значение текущего (первого) элемента массива currentItem.

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

  • Вторым аргументом reduce может быть начальное значение initialValue. Это значение будет присвоено аккумулятору до применения callback-функции к первому элементу массива.

Допустим у нас есть следующая задача: из массива постов твиттера отдельного пользователя необходимо посчитать сумму всех лайков. Можно перебрать циклом for или forEach, каждое из этих решений потребует дополнительного кода. А можно использовать reduce.

Заметили свойство tags у каждого поста? Продолжая тему reduce, мы соберем в массив все теги, которые встречаются в постах.

После того, как мы собрали все теги из постов, хорошо бы было посчитать количество уникальных тегов в массиве. И снова reduce тут как тут.

8. Array.prototype.sort()

Позволяет сортировать элементы массива на месте. Помимо возврата отсортированного массива, метод sort также отсортирует массив, на котором он был вызван. По умолчанию метод sort сортирует, преобразуя элементы к строке.

  • Перебирает

  • Изменяет

  • Возвращает коллекцию

8.1. Свой порядок сортировки

Для указания своего порядка сортировки в метод arr.sort(fn) нужно передать функцию fn с двумя параметрами, которая сравнивает их. Внутренний алгоритм функции сортировки умеет сортировать любые массивы. Но для этого ему нужно знать, как их сравнивать. Эту роль и выполняет fn.

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

  • Положительное значение, если a > b

  • Отрицательное значение, если a < b

  • Если равны – можно 0, но вообще не важно, что возвращать, если их взаимный порядок не имеет значения.

Отсортируем массив наших пользователей по возрастанию дней онлайн активности.

Array.sort на MDN

9. Цепочки методов массива

Есть массив чисел, из него необходимо взять все четные и умножить на 2, после чего еще и развернуть массив. Выразим кодом решение так, как мы уже умеем это делать.

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

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

Last updated