Освоите методы фильтрации, сопоставления, сокращения и других методов массива
Цикл for
сослужил нам хорошую службу, но теперь пора избавиться от него в пользу методов массива. Давайте рассмотрим несколько примеров и посмотрим, что вы думаете.
Во всех примерах мы будем обрабатывать один и тот же список телешоу. Вот:
фильтр
Рассмотрим следующий пример, в котором из списка телешоу выбираются только ситкомы. Он все еще использует цикл for
:
Мы начинаем с пустого массива ситкомов, перебираем список шоу и вставляем в него только ситкомы.
Можем ли мы сделать лучше, чем это?
Метод массива filter
выбирает элементы из списка с помощью функции предиката. filter
не изменяет входной массив. Создает новый.
Предикат - это функция, которая проверяет выполнение условия и возвращает логическое значение (true
или false
).
Вот наша функция предиката, проверяющая, является ли телешоу ситкомом:
function isSitcom(show){ return show.type === 'sitcom'; }
Теперь мы можем передать функцию предиката методу массива filter
, чтобы выбрать только ситкомы из списка:
const sitcoms = shows.filter(isSitcom);
Вот и все. Что вы думаете?
карта
Теперь мы хотим преобразовать список объектов телешоу в список строк. Для каждого объекта мы хотим создать новую строку, подобную этой: `${show.name} is a ${show.type}`
.
Вот как выполняется преобразование с помощью цикла for
:
Мы начинаем с пустого массива строк, просматриваем список телешоу и добавляем в него вычисленные тексты строк.
Я думаю, мы можем добиться большего.
Преобразование массивов в новые массивы с тем же количеством элементов правильно выполняется с map
.
Метод массива map
преобразует список значений в новый список значений. Новые значения могут быть любыми, от примитивов до объектов. map
не изменяет входной массив. Создает новый.
Вот наша функция отображения, преобразующая объект в строку:
function toShowText(show){ return `${show.name} is a ${show.type}`; }
Мы можем передать функцию сопоставления методу массива map
и выполнить то же преобразование, что и раньше:
const showsTexts = shows.map(toShowText);
Как вы думаете, это выглядит лучше?
уменьшать
Рассмотрим следующий код, использующий цикл for
для определения количества шоу для каждого типа:
Мы начинаем с пустого объекта ({}
), перебираем список шоу и на каждом шаге увеличиваем счетчик для типа текущего телешоу.
Ниже вы можете проверить, как увеличиваются счетчики на каждом шаге:
Первое шоу - ситком, поэтому счетчик для него установлен на 1
. Второй сериал по-прежнему является ситкомом, поэтому количество ситкомов увеличено до 2
. Третье шоу - ситком, поэтому счет становится 3
. Четвертое шоу - приключение, поэтому счет для ситкомов остается 3
, а для приключений устанавливается 1
.
Давайте проведем рефакторинг кода, используя методы массива.
Метод массива reduce
преобразует список значений в новое агрегированное значение с помощью функции редуктора.
На каждом шаге функция редуктора принимает агрегированное значение и текущий элемент и возвращает вновь вычисленное агрегированное значение.
Вот наша функция-редуктор, которая принимает совокупный объект со счетчиками для каждого типа и текущего шоу и возвращает совокупный объект с увеличенными счетчиками для текущего типа шоу:
function countByType(counts, show){ counts[show.type] = (counts[show.type] || 0 ) + 1; return counts; }
Выражение (counts[show.type] || 0 )
возвращает счетчик для определенного типа шоу, если этот тип существует. В противном случае он оценивается как 0
.
Затем мы можем передать функцию редуктора методу reduce
и вычислить тот же результат, что и предыдущая логика цикла:
const counts = shows.reduce(countByType, {})
Второй аргумент метода reduce
- это начальное значение для вычисленного совокупного значения. В нашем примере это пустой объект ({}
).
каждые / некоторые
В следующих примерах используется for
цикл, чтобы определить, все ли шоу являются ситкомами и есть ли в списке хотя бы один ситком.
Мы начинаем с переменной areAllSicoms
, равной true
, и просматриваем список в цикле. Когда мы находим шоу, которое не является ситкомом, мы устанавливаем его на false
и останавливаем цикл:
Аналогичным образом мы начинаем с переменной hasSitcoms
, равной false
, и просматриваем список. Когда мы находим ситком, мы устанавливаем true
и останавливаем цикл:
Думаю, мы можем улучшить этот код.
Метод every
проверяет, все ли элементы в массиве проходят проверку от функции предиката, и возвращает логическое значение. Если функция предиката возвращает ложное значение, она останавливается и возвращает false
. В противном случае он возвращает true
после обработки всех элементов.
Метод some
проверяет, проходит ли хотя бы один элемент в массиве тест из функции предиката, и возвращает логическое значение. Если функция предиката возвращает истинное значение, она останавливается и возвращает true
. В противном случае он возвращает false
после обработки всех элементов.
Ниже приведена функция предиката, которую мы можем использовать для них обоих, чтобы проверить, является ли шоу ситкомом:
function isSitcom(show){ return show.type === 'sitcom'; }
Теперь мы можем передать функцию предиката в методы массива every
и some
, чтобы определить, все ли шоу являются ситкомами и есть ли хотя бы один ситком в списке:
Как ты думаешь, сейчас это выглядит лучше?
найти
Ниже приведен пример цикла поиска определенного телешоу в списке:
Мы начинаем с переменной sitcom
, равной null
, и просматриваем список в цикле. Когда мы находим шоу с определенным именем, мы устанавливаем переменную для ссылки на этот объект и останавливаем цикл.
Можем ли мы упростить этот код?
Метод find
возвращает первый элемент из массива, удовлетворяющий функции предиката. Если элемент не найден, возвращается undefined
.
Вот наша функция-предикат, проверяющая название шоу, которое мы ищем:
function isFriendsSitcom(show){ return show.name === 'Friends'; }
Теперь мы можем передать функцию предиката методу массива find
:
let sitcom = shows.find(isFriendsSitcom);
Аналогичную функцию предиката можно реализовать с помощью стрелочной функции. Вот как это выглядит:
const sitcom = shows.find(show => show.name === 'Friends');
Как ты думаешь, сейчас это выглядит лучше?
Заключение
Это были одни из самых полезных методов массива, которые вы можете использовать для рефакторинга for
циклов. В моей предыдущей статье вы можете найти еще несколько идей о том, как преобразовать код в функциональный стиль.
Спасибо за прочтение.