Массив: перебирающие методы
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/array-methods.
Современный стандарт JavaScript предоставляет много методов для «умного» перебора массивов, которые есть в современных браузерах…
…Ну а для их поддержки в IE8- просто подключите библиотеку ES5-shim.
forEach
Метод «arr.forEach(callback[, thisArg])» используется для перебора массива.
Он для каждого элемента массива вызывает функцию callback .
Этой функции он передаёт три параметра callback(item, i, arr) :
- item – очередной элемент массива.
- i – его номер.
- arr – массив, который перебирается.
var arr = ["Яблоко", "Апельсин", "Груша"]; arr.forEach(function(item, i, arr) < alert( i + ": " + item + " (массив:" + arr + ")" ); >);
Второй, необязательный аргумент forEach позволяет указать контекст this для callback . Мы обсудим его в деталях чуть позже, сейчас он нам не важен.
Метод forEach ничего не возвращает, его используют только для перебора, как более «элегантный» вариант, чем обычный цикл for .
filter
Метод «arr.filter(callback[, thisArg])» используется для фильтрации массива через функцию.
Он создаёт новый массив, в который войдут только те элементы arr , для которых вызов callback(item, i, arr) возвратит true .
var arr = [1, -1, 2, -2, 3]; var positiveArr = arr.filter(function(number) < return number >0; >); alert( positiveArr ); // 1,2,3
map
Метод «arr.map(callback[, thisArg])» используется для трансформации массива.
Он создаёт новый массив, который будет состоять из результатов вызова callback(item, i, arr) для каждого элемента arr .
var names = ['HTML', 'CSS', 'JavaScript']; var nameLengths = names.map(function(name) < return name.length; >); // получили массив с длинами alert( nameLengths ); // 4,3,10
every/some
Эти методы используются для проверки массива.
- Метод «arr.every(callback[, thisArg])» возвращает true , если вызов callback вернёт true для каждого элемента arr .
- Метод «arr.some(callback[, thisArg])» возвращает true , если вызов callback вернёт true для какого-нибудь элемента arr .
var arr = [1, -1, 2, -2, 3]; function isPositive(number) < return number >0; > alert( arr.every(isPositive) ); // false, не все положительные alert( arr.some(isPositive) ); // true, есть хоть одно положительное
reduce/reduceRight
Метод «arr.reduce(callback[, initialValue])» используется для последовательной обработки каждого элемента массива с сохранением промежуточного результата.
Это один из самых сложных методов для работы с массивами. Но его стоит освоить, потому что временами с его помощью можно в несколько строк решить задачу, которая иначе потребовала бы в разы больше места и времени.
Метод reduce используется для вычисления на основе массива какого-либо единого значения, иначе говорят «для свёртки массива». Чуть далее мы разберём пример для вычисления суммы.
Он применяет функцию callback по очереди к каждому элементу массива слева направо, сохраняя при этом промежуточный результат.
Аргументы функции callback(previousValue, currentItem, index, arr) :
- previousValue – последний результат вызова функции, он же «промежуточный результат».
- currentItem – текущий элемент массива, элементы перебираются по очереди слева-направо.
- index – номер текущего элемента.
- arr – обрабатываемый массив.
Кроме callback , методу можно передать «начальное значение» – аргумент initialValue . Если он есть, то на первом вызове значение previousValue будет равно initialValue , а если у reduce нет второго аргумента, то оно равно первому элементу массива, а перебор начинается со второго.
Проще всего понять работу метода reduce на примере.
Например, в качестве «свёртки» мы хотим получить сумму всех элементов массива.
Вот решение в одну строку:
var arr = [1, 2, 3, 4, 5] // для каждого элемента массива запустить функцию, // промежуточный результат передавать первым аргументом далее var result = arr.reduce(function(sum, current) < return sum + current; >, 0); alert( result ); // 15
Разберём, что в нём происходит.
При первом запуске sum – исходное значение, с которого начинаются вычисления, равно нулю (второй аргумент reduce ).
Сначала анонимная функция вызывается с этим начальным значением и первым элементом массива, результат запоминается и передаётся в следующий вызов, уже со вторым аргументом массива, затем новое значение участвует в вычислениях с третьим аргументом и так далее.
Поток вычислений получается такой
В виде таблицы где каждая строка – вызов функции на очередном элементе массива:
sum | current | результат | |
---|---|---|---|
первый вызов | 0 | 1 | 1 |
второй вызов | 1 | 2 | 3 |
третий вызов | 3 | 3 | 6 |
четвёртый вызов | 6 | 4 | 10 |
пятый вызов | 10 | 5 | 15 |
Как видно, результат предыдущего вызова передаётся в первый аргумент следующего.
Кстати, полный набор аргументов функции для reduce включает в себя function(sum, current, i, array) , то есть номер текущего вызова i и весь массив arr , но здесь в них нет нужды.
Посмотрим, что будет, если не указать initialValue в вызове arr.reduce :
var arr = [1, 2, 3, 4, 5] // убрали 0 в конце var result = arr.reduce(function(sum, current) < return sum + current >); alert( result ); // 15
Результат – точно такой же! Это потому, что при отсутствии initialValue в качестве первого значения берётся первый элемент массива, а перебор стартует со второго.
Таблица вычислений будет такая же, за вычетом первой строки.
Метод arr.reduceRight работает аналогично, но идёт по массиву справа-налево.
Итого
Мы рассмотрели методы:
- forEach – для перебора массива.
- filter – для фильтрации массива.
- every/some – для проверки массива.
- map – для трансформации массива в массив.
- reduce/reduceRight – для прохода по массиву с вычислением значения.
Во многих ситуациях их использование позволяет написать код короче и понятнее, чем обычный перебор через for .
Javascript: 7 способов перебрать массив
Рассмотрим семь вариантов, как перебрать массив в js.
Цикл For
Пожалуй самый популярный способ проитерировать массив.
let arrData = ['php', 'js', 'mysql', 'python']; for (i=0;i
Цикл While
Второй по популярности способ перебора, будет итерировать пока условие true (верно). Другими словами, пока переменная i меньше длины массива.
let arrData = ['php', 'js', 'mysql', 'python']; let i = 0; while(i
Цикл forEach
Существует для итерации коллекций. Коллекция может быть массивом или списком. В каждой итерации, получаем 2 аргумента. Первый — это сам элемент массива. Второй — это его индекс.
let arrData = ['php', 'js', 'mysql', 'python']; arrData.forEach((item,index) => < console.log(item); >);
Every()
Метод every выполняет функцию для каждого элемента массива. В данном случае, мы передаем в метод every, функцию logger для вывода каждого элемента в консоль и завершаем каждую итерацию, возвращая true. Чтобы цикл не остановился.
let arrData = ['php', 'js', 'mysql', 'python']; const logger = ((element) => < console.log(element); return true; >) arrData.every(logger);
Метод every() вызывает переданную функцию callback один раз для каждого элемента, присутствующего в массиве, пока не найдёт такой, для которого callback вернёт false.
Some()
Метод some() проверяет, проходит ли хотя бы один элемент в массиве тест, реализованный переданной функцией.
let arrData = ['php', 'js', 'mysql', 'python']; let someTrigger = arrData.some((val, index, array) => < console.log(val); >)
Filter()
Метод filter() создает новый массив, заполненный элементами, прошедшими проверку, переданной функцией.
let arrData = ['php', 'js', 'mysql', 'python']; let filterTrigger = arrData.filter((item) => < console.log(item); return true; >)
Map()
Метод map(), перебирает массив и создает новый, где каждый элемент является результатом callback функции.
let arrData = ['php', 'js', 'mysql', 'python']; let newArr = arrData.map((item) => < console.log(item); >)
Цикл for — JS: Массивы
Работа с массивами почти всегда завязана на одновременную обработку всех его элементов. Это нужно при выводе списков на экран, при выполнении различных расчетов или проверке данных. Во всех этих случаях нужен механизм для перебора элементов массива. Самый простой способ сделать это – использовать цикл.
Обход
Циклы напрямую с массивами не связаны, но у циклов есть счетчик, который может выступать в качестве индекса массива. Поэтому соединить их не составляет никакого труда:
// Создаем массив const userNames = ['petya', 'vasya', 'evgeny']; // Определяем цикл // Начальное значение счетчика i = 0 – вычисляется один раз перед началом выполнения // Условие остановки i < userNames.length – выполняется перед каждой итерацией// Изменение счетчика i += 1 – выполняется после каждой итерации for (let i = 0; i userNames.length; i += 1) // Этот код выполняется для каждого элемента console.log(userNames[i]); > // => 'petya' // => 'vasya' // => 'evgeny'
В данном коде создаем массив из трех элементов — имен. Далее в цикле обходим массив и выводим на экран все имена так, что каждое имя оказывается на новой строке ( console.log автоматически делает перевод строки).
Рассмотрим этот этап подробнее. При обходе массива циклом for счетчик, как правило, играет роль индекса в массиве. Он инициализируется нулем и увеличивается до userNames.length — 1 , что соответствует индексу последнего элемента. Именно поэтому мы используем строгое сравнение < (меньше) в условном выражении i < userNames.length , а не меньше либо равно).
А что, если нам нужно вывести значения в обратном порядке? Для этого есть два способа. Один — идти в прямом порядке, то есть от нулевого индекса до последнего, и каждый раз вычислять нужный индекс по такой формуле размер массива — 1 — текущее значение счетчика .
const userNames = ['petya', 'vasya', 'evgeny']; for (let i = 0; i userNames.length; i += 1) const index = (userNames.length - 1) - i; console.log(userNames[index]); >
Другой способ подразумевает обход в обратном порядке, от верхней границы до нижней, то есть от последнего индекса массива к первому (нулю, так как индексирование начинается с нуля). В такой ситуации код меняется на следующий:
const userNames = ['petya', 'vasya', 'evgeny']; // Начальное значение i соответствует последнему индексу в массиве for (let i = userNames.length - 1; i >= 0; i -= 1) console.log(userNames[i]); >
При таком обходе проверка остановки должна быть именно на >= , иначе элемент с индексом 0 не попадет в цикл.
Изменение
Во время обхода массива его можно не только читать, но и модифицировать. Предположим, что перед нами стоит задача нормализации списка электронных адресов — например, приведение их к нижнему регистру. Тогда код будет выглядеть так:
const emails = ['VASYA@gmAil.com', 'iGoR@yandex.RU', 'netiD@hot.CoM']; console.log(emails); // => [ 'VASYA@gmAil.com', 'iGoR@yandex.RU', 'netiD@hot.CoM' ] for (let i = 0; i emails.length; i += 1) const email = emails[i]; // toLowerCase() — стандартный метод js, // преобразующий строку в нижний регистр const normalizedEmail = email.toLowerCase(); // Заменяем значение emails[i] = normalizedEmail; > console.log(emails); // => [ 'vasya@gmail.com', 'igor@yandex.ru', 'netid@hot.com' ]
Ключевая строчка: emails[i] = normalizedEmail; . В ней происходит перезапись элемента под индексом i .
Резюме
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Методы перебора массива (map, filter, reduce)
Язык JavaScript оказывает явное предпочтение массивам перед другими структурами данных. У них много удобных специфических фишек, например, целый набор перебирающих методов: map , filter , reduce .
map
Метод map() создаёт новый массив с результатом вызова указанной функции⚙️ для каждого элемента массива.
Видео
Синтаксис
let new_array = arr.map(function callback( currentValue[, index[, array]]) // Возвращает элемент для new_array >[, thisArg])
Метод map вызывает переданную функцию⚙️ callback один раз для каждого элемента, в порядке их появления и конструирует новый массив из результатов её вызова. Функция⚙️ callback вызывается только для индексов массива, имеющих присвоенные значения, включая undefined . Она не вызывается для пропущенных элементов массива (то есть для индексов, которые никогда не были заданы, были удалены или им никогда не было присвоено значение).
Функция⚙️ callback вызывается с тремя аргументами:
- значением элемента,
- индексом элемента
- и массивом, по которому осуществляется проход.
Если в метод map был передан параметр thisArg , при вызове callback он будет использоваться в качестве значения this . В противном случае в качестве значения this будет использоваться значение undefined . В конечном итоге значение this , наблюдаемое из функции⚙️ callback , определяется согласно обычным правилам определения this , видимого из функции⚙️.
Метод map не изменяет массив, для которого он был вызван (хотя функция⚙️ может это делать!).
Диапазон элементов, обрабатываемых методом map , устанавливается до первого вызова функции⚙️ callback . Элементы, добавленные в массив после начала выполнения метода map , не будут посещены функцией⚙️ callback . Если существующие элементы массива изменяются функцией⚙️ callback , их значения, переданные в функцию⚙️, будут значениями на тот момент времени, когда метод map посетит их. Удалённые элементы посещены не будут.
Примеры:
простой пример
У вас есть массив со множеством объектов, каждый из которых представляет отдельного человека. Тут может быть очень много данных: имя, возраст, цвет волос и любимый персонаж из кинематографа, но в данный момент всё это не требуется – вы хотите получить только массив паспортных номеров этих людей, чтобы выдать им всем пропуска на конференцию.
Интерактивный редактор
function learnJavaScript()const friends = [passport: '03005988', name: 'Joseph Francis Tribbiani Jr', age: 32, sex: 'm' >,passport: '03005989', name: 'Chandler Muriel Bing', age: 33, sex: 'm' >,passport: '03005990', name: 'Ross Eustace Geller', age: 33, sex: 'm' >,passport: '03005991', name: 'Rachel Karen Green', age: 31, sex: 'f' >,passport: '03005992', name: 'Monica Geller', age: 31, sex: 'f' >,passport: '03005993', name: 'Phoebe Buffay', age: 34, sex: 'f' >]let passports = friends.map(friend => friend.passport + ' ')return passports>
В определенных случаях вам может понадобится отобразить массив объектов с выбранными ключами в виде строки :
Интерактивный редактор
function learnJavaScript()const users = [id: 11, name: 'Adam', age: 23, group: 'editor' >,id: 47, name: 'John', age: 28, group: 'admin' >,id: 85, name: 'William', age: 34, group: 'editor' >,id: 97, name: 'Oliver', age: 28, group: 'admin' >]let result = users.map(( id, age, group >) => `\n$id> $age> $group>`).join('')return result>
Создание массива значений Фаренгейта из массива значений Цельсия:
Пример с обработкой каждого элемента массива заданной формулой :
Интерактивный редактор
function learnJavaScript()let celsius = [-15, -5, 0, 10, 16, 20, 24, 32]let fahrenheit = celsius.map(t => t * 1.8 + 32 + ' ')return fahrenheit>
Отображение массива чисел с использованием функции, содержащей аргумент :
Интерактивный редактор
function learnJavaScript()const numbers = [1, 4, 9]const doubles = numbers.map(num => num * 2 + ' ')return doubles>
filter
Метод filter() создаёт новый массив со всеми элементами, прошедшими проверку, задаваемую в передаваемой функции⚙️.
Результатом работы filter всегда является массив. Если функция⚙️ для элемента возвращает true (или любое «правдивое» значение), этот элемент попадает в результат, иначе – не попадает.
Синтаксис
let newArray = arr.filter(function callback(element[, index, [array]])[, thisArg])
Описание
Метод filter() вызывает переданную функцию⚙️ callback один раз для каждого элемента, присутствующего в массиве, и конструирует новый массив со всеми значениями, для которых функция⚙️ callback вернула true или значение, становящееся true при приведении в boolean . Функция⚙️ callback вызывается только для индексов массива, имеющих присвоенные значения; она не вызывается для индексов, которые были удалены или им значения никогда не присваивались. Элементы массива, не прошедшие проверку функцией⚙️ callback , просто пропускаются и не включаются в новый массив.
Функция⚙️ callback вызывается с тремя аргументами:
- значение элемента;
- индекс элемента;
- массив, по которому осуществляется проход.
Если в метод filter() был передан параметр thisArg , при вызове функции⚙️ он будет использоваться в качестве значения this . В противном случае в качестве значения this будет использоваться значение undefined . В конечном итоге значение this , наблюдаемое из функции⚙️, определяется согласно обычным правилам определения this , видимого из функции⚙️.
Метод filter() не изменяет массив, для которого он был вызван.
Диапазон элементов, обрабатываемых методом filter() , устанавливается до первого вызова функции⚙️ callback . Элементы, добавленные в массив после начала выполнения метода filter() , не будут посещены функцией⚙️ callback . Если существующие элементы массива изменятся, значения, переданные в функцию⚙️ callback , будут значениями на тот момент времени, когда метод filter() посетит их. Удалённые элементы посещены не будут.
Пример
Отфильтровывание всех маленьких значений
Следующий пример использует filter() для создания отфильтрованного массива, все элементы которого больше или равны value , а все меньшие value удалены.
Интерактивный редактор
function learnJavaScript()const isBigEnough = value => value >= 10let filtered = [12, 5, 8, 130, 44].filter(isBigEnough) + ' 'return filtered>
reduce
Метод reduce также запускается в контексте массива и вызывает функцию⚙️ для каждого элемента, но помимо этого, он аккумулирует результаты всех вызовов в одно значение. Этим поведением можно управлять.
reduce предназначен не для того, чтобы изменять элементы коллекции, как map . Его задача – подсчитать «сумму» всех элементов тем или иным способом, и вернуть ее.
Результирующим значением может быть что угодно: число, строка, объект, массив – все зависит от задачи, которую решает JavaScript разработчик.
Метод reduce принимает 2 параметра:
- функция, как и map , который будет вызван последовательно для каждого элемента коллекции;
- начальное значение аккумулятора.
В функции⚙️ тоже 2 аргумента:
- первый – это накопленное значение (аккумулятор);
- непосредственно элемент массива.
Синтаксис
array.reduce(function callback[, initialValue])
Описание
Метод reduce() выполняет функцию⚙️ callback один раз для каждого элемента, присутствующего в массиве, за исключением пустот, принимая четыре аргумента: начальное значение (или значение от предыдущего вызова callback ), значение текущего элемента, текущий индекс и массив, по которому происходит итерация.
При первом вызове функции⚙️, параметры accumulator и currentValue могут принимать одно из двух значений. Если при вызове reduce() передан аргумент initialValue , то значение accumulator будет равным значению initialValue , а значение currentValue будет равным первому значению в массиве. Если аргумент initialValue не задан, то значение accumulator будет равным первому значению в массиве, а значение currentValue будет равным второму значению в массиве.
Если массив пустой и аргумент initialValue не указан, будет брошено исключение TypeError . Если массив состоит только из одного элемента (независимо от его положения в массиве) и аргумент initialValue не указан, или если аргумент initialValue указан, но массив пустой, то будет возвращено одно это значение, без вызова функции⚙️ callback .
Начальное значение аккумулятора
Разберемся с начальным значением. В примере оно равно 0 , так как мы считаем численное значение – сумму возрастов. На месте нуля может быть любое другое число/строка (пустая или нет)/объект/массив – любое значение, с которого вы начинаете аккумуляцию. Для примера объединим имена всех друзей в одну строчку :
Интерактивный редактор
function learnJavaScript()const friends = [passport: '03005988', name: 'Joseph Francis Tribbiani Jr', age: 32, sex: 'm' >,passport: '03005989', name: 'Chandler Muriel Bing', age: 33, sex: 'm' >,passport: '03005990', name: 'Ross Eustace Geller', age: 33, sex: 'm' >,passport: '03005991', name: 'Rachel Karen Green', age: 31, sex: 'f' >,passport: '03005992', name: 'Monica Geller', age: 31, sex: 'f' >,passport: '03005993', name: 'Phoebe Buffay', age: 34, sex: 'f' >]const names = friends.reduce((accumulator, friend) => `$accumulator> $friend.name>, `, 'Friends: ')return names>
Здесь исходным значением послужила строка «Friends:» , к которой постепенно добавились имена всех друзей.
Если вы не указываете исходное значение явно, им неявно становится первый 1️⃣ элемент массива. В этом случае функция⚙️ для него уже не вызывается.
Пример
Суммирование всех значений в массиве:
Интерактивный редактор
function learnJavaScript()const initialValue = 0const sum = [1, 2, 3].reduce((accumulator, currentValue) =>return accumulator + currentValue>, initialValue)return sum>
И тоже самое в одну строчку кода:
Интерактивный редактор
function learnJavaScript()const sum = [1, 2, 3].reduce((x, y) => x + y)return sum>
chaining
Программирование на JavaScript поддерживает удобный паттерн чейнинг ( chaining ) – объединение нескольких функций⚙️ в одну цепочку с последовательной передачей результата.
Все три разобранных метода вызываются в контексте массива, а два 2️⃣ из них еще и возвращают массив. Таким образом, их очень легко объединить.
Например, посчитаем общий возраст всех мальчиков :
Интерактивный редактор
function learnJavaScript()const friends = [passport: '03005988', name: 'Joseph Francis Tribbiani Jr', age: 32, sex: 'm' >,passport: '03005989', name: 'Chandler Muriel Bing', age: 33, sex: 'm' >,passport: '03005990', name: 'Ross Eustace Geller', age: 33, sex: 'm' >,passport: '03005991', name: 'Rachel Karen Green', age: 31, sex: 'f' >,passport: '03005992', name: 'Monica Geller', age: 31, sex: 'f' >,passport: '03005993', name: 'Phoebe Buffay', age: 34, sex: 'f' >]let totalBoysYears = friends.filter(friend => friend.sex === 'm').reduce((accumulator, friend) => accumulator + friend.age, 0)return totalBoysYears>
Или соберем номера паспортов девочек, чтобы купить им билеты на самолет до Лас-Вегаса :
Интерактивный редактор
function learnJavaScript()const friends = [passport: '03005988', name: 'Joseph Francis Tribbiani Jr', age: 32, sex: 'm' >,passport: '03005989', name: 'Chandler Muriel Bing', age: 33, sex: 'm' >,passport: '03005990', name: 'Ross Eustace Geller', age: 33, sex: 'm' >,passport: '03005991', name: 'Rachel Karen Green', age: 31, sex: 'f' >,passport: '03005992', name: 'Monica Geller', age: 31, sex: 'f' >,passport: '03005993', name: 'Phoebe Buffay', age: 34, sex: 'f' >]let girlsPassports = friends.filter(friend => friend.sex === 'f').map(friend => friend.passport) + ' 'return girlsPassports>
Заключение
С использованием этих замечательных функций⚙️ код стало читать удобнее. Итак, ниже приведен список статей, в которых более подробна рассмотрена эта тема.
Проблемы?
Пишите в Discord или телеграмм чат, а также подписывайтесь на наши новости
Вопросы:
Функция, вызываемая для каждого элемента массива?
Метод, который создаёт новый массив с результатом вызова указанной функции для каждого элемента массива:
Результирующим значением метода reduce может выступать:
Суммирование всех значений в массиве достигается методом:
Метод, который создаёт новый массив со всеми элементами, прошедшими проверку, задаваемую в передаваемой функции:
Объединение нескольких функций в одну цепочку с последовательной передачей результата:
Для того чтобы понять, на сколько вы усвоили этот урок, пройдите тест в мобильном приложении нашей школы по этой теме или в нашем телеграм боте.
Ссылки:
- Упрости свой JavaScript – используй map, reduce и filter
- 15 Полезных javascript примеров map(), reduce() и filter()
- Array.prototype.map()
- Array.prototype.filter()
- Array.prototype.reduce()
Contributors ✨
Thanks goes to these wonderful people (emoji key):