Кратко
СкопированоМетод map позволяет трансформировать один массив в другой при помощи функций-колбэка. Переданная функция будет вызвана для каждого элемента массива по порядку. Из результатов вызова функции будет собран новый массив.
Пример
СкопированоСоздадим массив квадратов:
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]const squares = nums.map(function (num) { return num * num})console.log(squares)// [1, 4, 9, 16, 25, 36, 49, 64, 81]
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const squares = nums.map(function (num) {
return num * num
})
console.log(squares)
// [1, 4, 9, 16, 25, 36, 49, 64, 81]
Либо можно сделать массив с объектами:
const objects = nums.map(function (num) { return { field: num, }})console.log(objects)// [// { field: 1 },// { field: 2 },// ...// { field: 9 }// ]
const objects = nums.map(function (num) {
return {
field: num,
}
})
console.log(objects)
// [
// { field: 1 },
// { field: 2 },
// ...
// { field: 9 }
// ]
Интерактивный пример:
Как пишется
СкопированоКак и другим похожим методам, map необходимо передать колбэк-функцию, которая будет возвращать какое-то значение. Именно это значение попадёт в итоговый трансформированный массив.
Функция, которую мы передаём в метод map, может принимать три параметра:
item— элемент массива в текущей итерации;index— индекс текущего элемента;arr— сам массив, который мы перебираем.
Суммируем числа, индексы и длины массива:
const nums = [0, 1, 2, 3]const transformed = nums.map(function (num, index, arr) { return num + index + arr.length})console.log(transformed)// [4, 6, 8, 10]
const nums = [0, 1, 2, 3]
const transformed = nums.map(function (num, index, arr) {
return num + index + arr.length
})
console.log(transformed)
// [4, 6, 8, 10]
Как понять
СкопированоЧасто возникают ситуации, когда на основе одного массива нужно создать другой массив, как-нибудь трансформировав исходные значения. Это можно сделать, используя обычные циклы for или while:
const nums = [1, 2, 3, 4, 5]const transformed = []for (let i = 0; i < nums.length; i++) { const num = nums[i] const item = `${i}-${num}` transformed.push(item)}console.log(transformed)// ['0-1', '1-2', '2-3', '3-4', '4-5']
const nums = [1, 2, 3, 4, 5]
const transformed = []
for (let i = 0; i < nums.length; i++) {
const num = nums[i]
const item = `${i}-${num}`
transformed.push(item)
}
console.log(transformed)
// ['0-1', '1-2', '2-3', '3-4', '4-5']
Задача решена, однако, как и другие встроенные методы массива, map позволяет написать код короче и проще для понимания:
const nums = [1, 2, 3, 4, 5]const transformed = nums.map(function (num, i) { return `${i}-${num}`})console.log(transformed)// ['0-1', '1-2', '2-3', '3-4', '4-5']
const nums = [1, 2, 3, 4, 5]
const transformed = nums.map(function (num, i) {
return `${i}-${num}`
})
console.log(transformed)
// ['0-1', '1-2', '2-3', '3-4', '4-5']
Результат тот же, но способ короче и проще.
Подсказки
Скопировано💡 map возвращает новый массив, при этом исходный массив никак не изменится.
💡 При работе с map необходимо возвращать значение из функции-колбэка. Если не вернуть значение — например, забыв обработать какую-то ветку условия, то в итоговом массиве будет undefined:
const nums = [1, 2, 3, 4, 5]const transformed = nums.map(function (num) { if (num <= 3) { return "less" } // Забыли обработать эту ветку условия})console.log(transformed)// ['less', 'less', 'less', undefined, undefined]
const nums = [1, 2, 3, 4, 5]
const transformed = nums.map(function (num) {
if (num <= 3) {
return "less"
}
// Забыли обработать эту ветку условия
})
console.log(transformed)
// ['less', 'less', 'less', undefined, undefined]
💡 Размер массива, которые возвращает map всегда совпадает с размером массива, который обходится.
💡 Функция-колбэк будет вызвана только для элементов имеющих установленное значения.
Создадим массив, используя конструктор с указанием размера массива Array. Все элементы этого массива являются незаполненными:
const newArray = Array(5)console.log("Размер массива:", newArray.length);// Размер массива: 5console.log(newArray)// [<5 empty items>]
const newArray = Array(5)
console.log("Размер массива:", newArray.length);
// Размер массива: 5
console.log(newArray)
// [<5 empty items>]
Попытаемся использовать метод map для установки в качестве значения элемента его индекс. В результате массив inited останется таким же пустым как и исходный массив new:
const initedArray = newArray.map(function (item, index) { console.log("элемент:", item) return index})console.log(initedArray)// [<5 empty items>]
const initedArray = newArray.map(function (item, index) {
console.log("элемент:", item)
return index
})
console.log(initedArray)
// [<5 empty items>]
Для решения этой проблемы можно воспользоваться деструктуризацией исходного массива:
const newArray = Array(5)console.log("Размер массива:", newArray.length)// Размер массива: 5const initedArray = [ ...newArray ].map(function (item, index) { console.log("элемент:", item) return index})// элемент: undefined// элемент: undefined// элемент: undefined// элемент: undefined// элемент: undefinedconsole.log(initedArray)// [ 0, 1, 2, 3, 4 ]
const newArray = Array(5)
console.log("Размер массива:", newArray.length)
// Размер массива: 5
const initedArray = [ ...newArray ].map(function (item, index) {
console.log("элемент:", item)
return index
})
// элемент: undefined
// элемент: undefined
// элемент: undefined
// элемент: undefined
// элемент: undefined
console.log(initedArray)
// [ 0, 1, 2, 3, 4 ]
💡 Для наполнения массива одинаковыми значениями можно воспользоваться рецептом Создание массива из большого количества повторяющихся элементов.
Передача контекста в колбэк-функцию
СкопированоВторым аргументом map может принимать значение, которое будет передано как контекст выполнения функции-колбэка:
const nums = [1, 2, 3]const otherData = { delta: 5 }const transformed = nums.map(function (num) { // this теперь ссылается на объект otherData return num + this.delta}, otherData)console.log(transformed)// [ 6, 7, 8 ]
const nums = [1, 2, 3]
const otherData = { delta: 5 }
const transformed = nums.map(function (num) {
// this теперь ссылается на объект otherData
return num + this.delta
}, otherData)
console.log(transformed)
// [ 6, 7, 8 ]
Обратите внимание, что стрелочным функциям нельзя изменить контекст выполнения, поэтому передача второго аргумента ни на что не повлияет:
const nums = [1, 2, 3]const otherData = { delta: 5 }const transformed = nums.map((num) => { // this.delta в данном случае равен undefined return num + this.delta}, otherData)console.log(transformed)// [ NaN, NaN, NaN ]
const nums = [1, 2, 3]
const otherData = { delta: 5 }
const transformed = nums.map((num) => {
// this.delta в данном случае равен undefined
return num + this.delta
}, otherData)
console.log(transformed)
// [ NaN, NaN, NaN ]
На практике
Скопированосоветует
Скопировано🛠 При работе с React или другой похожей на неё библиотекой map — это самый распространённый способ трансформировать массив данных в компоненты, которые в итоге будут на странице:
function SomeComponent() { const items = ['This', 'is', 'map!'] return ( <div> {items.map(item => <span>{item}</span>)} </div> )}
function SomeComponent() {
const items = ['This', 'is', 'map!']
return (
<div>
{items.map(item => <span>{item}</span>)}
</div>
)
}
🛠 Так как map возвращает массив, то у полученного массива мы можем продолжать по цепочке вызывать другие методы массива, в том числе, новый map, продолжая трансформацию новых данных:
const nums = [1, 2, 3, 4, 5]const result = nums.map(...).filter(...).map(...)
const nums = [1, 2, 3, 4, 5]
const result = nums.map(...).filter(...).map(...)
На собеседовании
Скопировано отвечает
СкопированоМетоды for и map определены на нескольких структурах данных. Мы рассмотрим чем отличаются эти методы для массивов.
Оба метода принимают колбэк, который вызывается для каждого элемента. Разница в том, что метод for ничего не возвращает, а метод map возвращает новый массив с результатами вызова колбэка на каждом исходном элементе. Если переданный колбэк ничего не возвращает в новом массиве появится undefined
Вы можете вернуть значение и из колбэка для for но оно никак не будет использоваться дальше.
[1,2,3].forEach(a => a + 3);
[1,2,3].forEach(a => a + 3);
Используя map вы можете создавать цепочки вызовов. Если же вы будете использовать for так сделать не получится.
const myArray = [4, 2, 8, 7, 3, 1, 0];const myArray2 = myArray.map(item => item * 2).sort((a, b) => a - b);console.log(myArray); // [4, 2, 8, 7, 3, 1, 0]console.log(myArray2); // [0, 2, 4, 6, 8, 14, 16]
const myArray = [4, 2, 8, 7, 3, 1, 0];
const myArray2 = myArray.map(item => item * 2).sort((a, b) => a - b);
console.log(myArray); // [4, 2, 8, 7, 3, 1, 0]
console.log(myArray2); // [0, 2, 4, 6, 8, 14, 16]
В примере выше изменился только my.
Для закрепления, реализуем ту же самую логику при помощи for.
const myArray = [4, 2, 8, 7, 3, 1, 0];let myArray2 = [];myArray.forEach(item => { myArray2.push(item * 2);});myArray2 = myArray2.sort((a, b) => a - b);console.log(myArray); // [4, 2, 8, 7, 3, 1, 0]console.log(myArray2); // [0, 2, 4, 6, 8, 14, 16]
const myArray = [4, 2, 8, 7, 3, 1, 0];
let myArray2 = [];
myArray.forEach(item => {
myArray2.push(item * 2);
});
myArray2 = myArray2.sort((a, b) => a - b);
console.log(myArray); // [4, 2, 8, 7, 3, 1, 0]
console.log(myArray2); // [0, 2, 4, 6, 8, 14, 16]