map() js — перебор и возвращение массива
Данный метод, в отличии от ранее рассмотренного метода forEach(), вернет нам новый массив, при этом исходный массив не изменяется.
Синтаксис данного метода аналогичен методу forEach
callback — функция, которая будет выполнена для каждого элемента массива.
Callback может быть стрелочной функцией и принимает такие параметры
- currentValue — значение текущего элемента массива
- index — порядковый номер элемента (начиная с 0)
- currentArray — массив, который мы перебираем
thisArg — это необязательный параметр. Значение, используемое в качестве this при вызове функции callback .
Давайте рассмотрим простой пример:
const arr = [1, 2, 3]; const newArr = arr.map((item, index) => < // увеличиваем значение каждого элемента на 1 // item - текущий элемент массива return item + 1; >); console.log(newArr); // [2, 3, 4] console.log(arr); // [1, 2, 3]
В качестве callback можно передать ранее созданную функцию:
const arr = [1, 2, 3]; function doThisForEachElement(item, index) < return item + 1; >const newArr = arr.map(doThisForEachElement); console.log(newArr); // [2, 3, 4]
Примеры использования метода map()
Теперь давайте рассмотрим еще несколько примеров.
Пример 1
Что будет если мы попробуем вернуть из колбека элементы по условию? Допустим из предыдущего примера, мы хотим вернуть только числа меньше или равные единице:
const arr = [1, 2, 3]; const newArr = arr.map(item => < if (item ); console.log(newArr); // [1, undefined, undefined]
В таком случае мы получим undefined для значений, которые не прошли условие. Если вам нужно вернуть не все значения в новый массив, а только те что удовлетворяют условию — тогда используйте метод filter()
Пример 2
Продолжим с массивами чисел. Допустим, нам нужно вернуть в новый массив числа возведенные в определенную степень. Как делать возведение в степень в JavaScript рассматривали в другом посте.
const arr = [2, 4, 5, 7]; const newArr = arr.map(item => < // возведем каждый элемент в третью степень return item ** 3; >); console.log(newArr); // [8, 64, 125, 343]
Также можно сделать упрощенный вариант записи, потому что мы сразу возвращаем измененное значение:
const newArr = arr.map(item => item ** 3);
Пример 3
Метод JS map() используется в React для рендеринга элементов. Вот как пример можете посмотреть код тут
У нас есть массив todos и на каждой итерации мы отрисовываем элемент li
Использование метода map() с объектами
Также мы можем использовать метод map() с массивом объектов и с самими объектами.
Пример 4
Допустим у нас есть массив пользователей и нам нужно провести определенные действия с каждым из пользователей — добавим свойство role :
const users = [ < id: 1, name: 'John', salary: 3000, position: 'developer' >, < id: 2, name: 'Kate', salary: 2800, position: 'designer' >, < id: 3, name: 'Bob', salary: 3200, position: 'manager' >]; const newArray = users.map(item => < item.role = 'admin'; return item; >); // Будет возвращен новый массив со свойством 'role' // для каждого пользователя console.log(newArray); //
В данном случае, если вы выведете в консоль массив users, то заметите что там тоже добавилось свойство role
Если нужно сохранить исходный массив неизменным, тогда нужно создать новый объект для этого и с помощью оператора spread скопировать свойства старого и добавить в него новые свойства:
const newArray = users.map(item => < return < . item, role: 'admin' >>); // Останется неизменным console.log(users); // Новый массив со свойством 'role' console.log(newArray);
Также можно задать условие и добавить разные свойства в зависимости от position :
const users = [ < id: 1, name: 'John', salary: 3000, position: 'developer' >, < id: 2, name: 'Kate', salary: 2800, position: 'designer' >, < id: 3, name: 'Bob', salary: 3200, position: 'manager' >]; const newArray = users.map(item => < if (item.position === 'manager') < return < . item, role: 'admin' >> return < . item, role: 'user' >>); // Role = admin будет добавлено только 3 пользователю // У остальных role будет = user console.log(newArray);
Или вот такая короткая запись с помощью тернарного оператора:
const newArray = users.map(item => item.position === 'manager' ? < . item, role: 'admin' >: < . item, role: 'user' >);
Своя реализация метода map
let array = [1, 5, 10, 15]; Array.prototype.customMap = function (callback, thisArg) < // Проверяем существует ли контекст вызова this (по умолчанию это сам массив) if (this == null) < throw new Error("It has to be array"); >let context = this; let obj = Object(this); // Проверям кол-во переданных аргументов // Если больше 1, значит был передан thisArg if (arguments.length > 1) < context = thisArg; >// Если callback это не функция, тогда выдаем оишбку if (typeof callback !== "function") < throw new Error("Callback has to be a function"); >// Длинаа переданного масива let len = obj.length; let newArray = []; let i = 0; // Для каждого элемента массива вызываем callback // И затем добавляем в массив, который в результат вернем while (i < len) < if (i in obj) < newArray[i] = callback.call(context, this[i], i, obj); >i++; > return newArray; >; // Теперь используем свой полифил const newArray = array.customMap(number => number + 1); console.log(newArray); // [2, 6, 11, 16]
Когда не следует использовать метод map()
Данный метод не следует использовать в таких случаях:
- Если вам нужен просто проход по массиву и вы не будете использовать возвращенный из данного метода массив. В таком случае лучше использовать forEach()
- Также когда функция (callback), которую вы передаете в качестве аргумента, не будет делать return
let array = [1, 5, 10, 15]; const newArray = array.map((item) => < item * 2; // не возвращается результат >); console.log(newArray); // [undefined, undefined, undefined, undefined]
Ваши вопросы и комментарии:
Свежие записи
Копирование материалов разрешено только с ссылкой на источник Web-Dev.guru
2023 © Все права защищены.
Массив: перебирающие методы
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице 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 .