О способах обхода массивов в JavaScript

Как обходить массивы правильно, профессионально и самое главное читабельно?
В JavaScript есть много способов обойти массив, и каждый из них служит для разных целей.

Как обходить массивы правильно, профессионально и самое главное читабельно?

В JavaScript есть много способов обойти массив, и каждый из них служит для разных целей. Наверно самый популярный из них это обход при помощи цикла for.

Однако в арсенале JavaScript есть более удобные в использовании и более выразительные средства для обхода массива. Однако многие разработчики ограничиваются только for, forEach или map.

О методах forEach, map, filter, every, some, flatMap

Разберем доступные методы подробнее. Начнем с методов forEach, map, filter, every, some, flatMap. Все эти методы появились еще в версии ES5, кроме flatMap, который появился в ES2019.

Почему я решил объединить их в общую группу? У всех этих методов одинаковая сигнатура параметров callback и thisArg.

callback

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

  • currentValue (обязательный) — текущий обрабатываемый элемент в массиве;
  • index (необязательный) — индекс текущего обрабатываемого элемента в массиве;
  • array (необязательный) — массив, по которому осуществляется обход.

thisArg

Необязательный аргумент. Значение, используемое в качестве this при вызове callback функции.

Передача thisArg — объект obj
Передача thisArg — объект obj

О чем необходимо помнить?

  • Сallback функция не вызывается для индексов, которые были удалены. Мутирование массива в callback функции не является хорошей практикой. Здесь такой подход использован лишь ради примера.
Для удаленных элементов callback не вызывается
Для удаленных элементов callback не вызывается
  • Сallback функция не вызывается для индексов, значения которым никогда не присваивались, например, для пропущенных элементов.
Callback не вызывается для пропущенных элементов
Callback не вызывается для пропущенных элементов
  • Однако, callback функция будет вызвана для элементов, которые присутствуют в массиве и имеют значение undefined.
Callback функция вызывается для элементов со значением undfined
Callback функция вызывается для элементов со значением undfined
  • Если необходимо обойти пропущенные элементы, нужно воспользоваться циклом for / for-of.
Обход пропущенных элементов при помощи цикла for
Обход пропущенных элементов при помощи цикла for
  • Callback функции можно передавать просто как имя функции, которая описана в другом месте, главное, чтобы аргументы совпадали. parseInt, который первым аргументом принимает значение, а вторым — основание системы счисления, является показательным примером.
Math.sqrt принимает один аргумент, parseInt -два аргумента
Math.sqrt принимает один аргумент, parseInt -два аргумента
  • Диапазон элементов, устанавливается до первого вызова callback функции. Элементы, добавленные в массив после начала выполнения метода, не будут посещены callback функцией.
Элементы, добавленные в массив после начала выполнения метода, не будут посещены callback функцией
Элементы, добавленные в массив после начала выполнения метода, не будут посещены callback функцией
  • Если существующие элементы массива изменятся, значения, переданные в функцию callback, будут значениями на тот момент времени, когда метод посетит их. Эти методы не делает копию массива перед итерацией.
Существующие элементы, которые изменили свое значение.
Существующие элементы, которые изменили свое значение.
  • thisArg имеет смысл использовать только если callback функция не является стрелочной. Так как все стрелочные функции лексически привязываются к значению this. В этом случае нужно объявить функцию с помощью функциональных выражений или через объявление функций.
Стрелочные функции лексически привязываются к значению this
Стрелочные функции лексически привязываются к значению this

Мы рассмотрели общие моменты, теперь рассмотрим каждый метод по отдельности.

forEach

  • Выполняет указанную функцию один раз для каждого элемента в массиве.
  • Способа остановить или прервать forEach — нет. Однако, можно выбросить и поймать исключение. Если вам необходимо такое поведение, метод forEach() неправильный выбор. Для этого лучше использовать for/for-of с break/continue.
Прерывание обхода массива с forEach и for
Прерывание обхода массива с forEach и for

map

  • Создаёт новый массив с результатом вызова указанной функции для каждого элемента массива.
Пример использования метода map
Пример использования метода map

filter

  • Создаёт новый массив со всеми элементами, которые удовлетворяют условию в callback функции.
  • Callback функция должна возвращать булевское значение (или приводимое к нему значение). Текущий обрабатываемый элемент попадет в результирующий массив, если функция вернет true.
  • Примеры использования: вывод всех нечетных чисел, вывод строк определенной длины и т.д.
Пример использования метода filter
Пример использования метода filter

every

  • Проверяет, удовлетворяют ли все элементы массива условию, заданному в передаваемой функции (как логическое И).
  • Возвращает true если функция проверки возвращает true для каждого элемента массива. Иначе - false.
  • Прерывает дальнейшее выполнение, как только найдется первый элемент, для которого callback функция вернет false.
Пример использования метода every
Пример использования метода every

some

  • Проверяет, удовлетворяет ли какой-либо элемент массива условию, заданному в callback функции (как логическое ИЛИ).
  • Метод возвращает true, если callback функция возвращает true хотя бы для одного элемента массива. Иначе - false.
  • Прерывает дальнейшее выполнение, как только найдется первый элемент, для которого callback функция вернет true.
Пример использования метода some
Пример использования метода some

flatMap

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

О методах reduce и reduceRight

Таким же образом опишем сначала общие моменты, а далее рассмотрим каждый метод отдельно. Эти методы:

  • Принимают два аргумента: callback и initialValue;
  • callback (обязательный) — функция, выполняющаяся для каждого элемента массива, принимает четыре аргумента:
    accumulator (обязательный) — аккумулирующее значение, которое возвращает функция callback после посещения очередного элемента;
    currentValue (обязательный) — текущий обрабатываемый элемент массива;
    index (необязательный) — индекс текущего обрабатываемого элемента массива;
    array (необязательный) — массив, для которого была вызвана функция reduce.
  • initialValue (необязательный) — объект, используемый в качестве значения при первом вызове callback функции;
  • Если массив пустой и аргумент initialValue не указан, будет брошено исключение TypeError;
Вызов метода reduce для пустого массива без initialValue вызывает исключение
Вызов метода reduce для пустого массива без initialValue вызывает исключение
  • В следующих случаях будет возвращено одно значение без вызова callback функции:
    если initialValue не указан и массив состоит только из одного элемента;
    если initialValue указан, но массив пустой;
В этих случаях callback функция не вызывается
В этих случаях callback функция не вызывается

reduce

  • Применяет функцию reducer к каждому элементу массива слева-направо, возвращая одно результирующее значение.
Пример использования метода reduce для сложения и умножения
Пример использования метода reduce для сложения и умножения
  • Если initialValue не задан, то значение accumulator будет равным первому значению в массиве, а значение currentValue будет равным второму значению в массиве.

reduceRight

  • Применяет функцию reducer к каждому элементу массива справа-налево, возвращая одно результирующее значение.
Пример использования метода reduceRight для сложения и умножения
Пример использования метода reduceRight для сложения и умножения
  • Если initialValue не задан, то значение accumulator будет равным последнему элементу в массиве, а значение currentValue будет равным второму с конца элементу в массиве.

Итоги

Мы рассмотрели различные способы обхода массивов и нюансы, связанные с каждым из этих способов: forEach, for/for-of, map, filter, every, some, flatMap, reduce, reduceRight.

Подписывайтесь на нас: