Кратко
СкопированоМетод 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]