Пошук уроків, статей та іншого контенту
Розглянете map для перетворення кожного елемента й побудови нового масиву без мутації початкового.
mapМетод map проходить по елементах масиву, застосовує до кожного з них callback-функцію та повертає новий масив із результатами.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((number) => number * 2);
console.log(doubled); // [2, 4, 6, 8]
console.log(numbers); // [1, 2, 3, 4]Початковий масив не змінюється. Саме тому map зручно використовувати для перетворення даних без мутації.
Назва методу походить від ідеї «відобразити» кожен елемент на нове значення:
1 → 2
2 → 4
3 → 6
4 → 8const newArray = array.map(callback);Callback-функція може отримувати три аргументи:
const newArray = array.map((element, index, array) => {
// Повертаємо значення для нового масиву
});element — поточний елемент;
index — індекс поточного елемента;
array — початковий масив.
Найчастіше достатньо використовувати лише element.
const prices = [100, 250, 80];
const pricesWithTax = prices.map((price) => price * 1.2);
console.log(pricesWithTax); // [120, 300, 96]Для кожного елемента prices callback повертає нову ціну. Метод map збирає всі повернуті значення в новий масив.
Якщо callback складається з одного виразу, можна використати скорочений синтаксис:
const numbers = [2, 4, 6];
const squares = numbers.map((number) => number ** 2);
console.log(squares); // [4, 16, 36]Якщо callback містить кілька інструкцій, потрібні фігурні дужки та явний return:
const numbers = [1, 2, 3];
const formattedNumbers = numbers.map((number) => {
const result = number * 10;
return `Результат: ${result}`;
});
console.log(formattedNumbers);
// ["Результат: 10", "Результат: 20", "Результат: 30"]Одна з найпоширеніших задач — отримати з масиву об’єктів масив інших значень.
const users = [
{ id: 1, name: "Олена", age: 28 },
{ id: 2, name: "Андрій", age: 34 },
{ id: 3, name: "Марія", age: 25 }
];
const userNames = users.map((user) => user.name);
console.log(userNames);
// ["Олена", "Андрій", "Марія"]Можна створювати нові об’єкти на основі старих:
const products = [
{ name: "Ноутбук", price: 30000 },
{ name: "Мишка", price: 800 }
];
const productCards = products.map((product) => ({
title: product.name,
formattedPrice: `${product.price} грн`
}));
console.log(productCards);
// [
// { title: "Ноутбук", formattedPrice: "30000 грн" },
// { title: "Мишка", formattedPrice: "800 грн" }
// ]Круглі дужки навколо об’єкта потрібні, щоб JavaScript сприйняв його як значення, яке повертається з arrow function:
const result = products.map((product) => ({
title: product.name
}));Без дужок фігурні дужки трактувалися б як тіло функції:
// Неправильно: callback нічого не повертає
const result = products.map((product) => {
title: product.name;
});Другий аргумент callback — це індекс поточного елемента.
const tasks = ["Зареєструватися", "Підтвердити email", "Створити пароль"];
const numberedTasks = tasks.map((task, index) => {
return `${index + 1}. ${task}`;
});
console.log(numberedTasks);
// [
// "1. Зареєструватися",
// "2. Підтвердити email",
// "3. Створити пароль"
// ]Індекс корисний, коли потрібно:
пронумерувати елементи;
додати позицію до об’єкта;
сформувати ключ або ідентифікатор;
виконати різне форматування залежно від позиції.
Наприклад:
const colors = ["red", "green", "blue"];
const colorOptions = colors.map((color, index) => ({
id: index + 1,
value: color
}));
console.log(colorOptions);
// [
// { id: 1, value: "red" },
// { id: 2, value: "green" },
// { id: 3, value: "blue" }
// ]map не змінює початковий масивmap створює новий масив, але це не означає, що вкладені об’єкти автоматично копіюються повністю.
Для масиву примітивних значень результат незалежний від початкового:
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => number * 2);
doubled[0] = 100;
console.log(doubled); // [100, 4, 6]
console.log(numbers); // [1, 2, 3]Під час перетворення об’єктів важливо розрізняти створення нового об’єкта та повернення того самого об’єкта:
const users = [
{ name: "Олена", active: true },
{ name: "Андрій", active: false }
];
const copiedUsers = users.map((user) => user);
copiedUsers[0].active = false;
console.log(users[0].active); // falseУ цьому прикладі map створив новий масив, але його елементи посилаються на ті самі об’єкти.
Якщо потрібно створити змінені копії об’єктів, використовуйте оператор розширення:
const users = [
{ name: "Олена", active: true },
{ name: "Андрій", active: false }
];
const inactiveUsers = users.map((user) => ({
...user,
active: false
}));
console.log(inactiveUsers);
// [
// { name: "Олена", active: false },
// { name: "Андрій", active: false }
// ]
console.log(users);
// [
// { name: "Олена", active: true },
// { name: "Андрій", active: false }
// ]Тут кожен результат є новим об’єктом, а початкові об’єкти залишаються без змін.
map завжди повертає масив тієї самої довжиниmap повертає по одному результату для кожного елемента початкового масиву.
const numbers = [1, 2, 3, 4];
const results = numbers.map((number) => {
if (number % 2 === 0) {
return number * 10;
}
return number;
});
console.log(results); // [1, 20, 3, 40]Якщо потрібно залишити лише частину елементів, використовуйте filter:
const numbers = [1, 2, 3, 4];
const evenNumbers = numbers.filter((number) => number % 2 === 0);
console.log(evenNumbers); // [2, 4]Методи можна поєднувати. Наприклад, спочатку залишити активних користувачів, а потім отримати їхні імена:
const users = [
{ name: "Олена", active: true },
{ name: "Андрій", active: false },
{ name: "Марія", active: true }
];
const activeUserNames = users
.filter((user) => user.active)
.map((user) => user.name);
console.log(activeUserNames); // ["Олена", "Марія"]Порядок важливий:
filter зменшує кількість елементів;
map перетворює кожен елемент.
forТу саму операцію можна виконати за допомогою циклу:
const numbers = [1, 2, 3];
const doubled = [];
for (const number of numbers) {
doubled.push(number * 2);
}
console.log(doubled); // [2, 4, 6]Варіант із map коротший і прямо описує мету операції:
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => number * 2);
console.log(doubled); // [2, 4, 6]map особливо доречний, коли потрібно:
пройти по всіх елементах;
перетворити кожен елемент;
отримати новий масив.
Якщо потрібно виконати побічну дію без створення нового масиву, краще використовувати forEach:
const users = ["Олена", "Андрій", "Марія"];
users.forEach((user) => {
console.log(`Користувач: ${user}`);
});Нехай сервер повернув список замовлень. Для відображення потрібно підготувати дані карток:
const orders = [
{
id: 101,
customer: "Олена",
items: 3,
total: 1250
},
{
id: 102,
customer: "Андрій",
items: 1,
total: 800
}
];
const orderCards = orders.map((order) => ({
id: order.id,
title: `Замовлення №${order.id}`,
description: `${order.customer}, товарів: ${order.items}`,
total: `${order.total} грн`
}));
console.log(orderCards);Результат:
[
{
id: 101,
title: "Замовлення №101",
description: "Олена, товарів: 3",
total: "1250 грн"
},
{
id: 102,
title: "Замовлення №102",
description: "Андрій, товарів: 1",
total: "800 грн"
}
]Такий підхід допомагає відокремити формат даних від початкової структури, отриманої від сервера.
mapmap не очікує завершення асинхронного callback. Якщо callback є async, результатом буде масив промісів:
const ids = [1, 2, 3];
const promises = ids.map(async (id) => {
return id * 10;
});
console.log(promises); // [Promise, Promise, Promise]Щоб дочекатися всіх результатів, використовуйте Promise.all:
const ids = [1, 2, 3];
async function getResults() {
const promises = ids.map(async (id) => {
// Імітація асинхронної операції
return id * 10;
});
const results = await Promise.all(promises);
console.log(results); // [10, 20, 30]
}
getResults();Promise.all повертає результати в тому самому порядку, що й початковий масив промісів.
returnЯкщо використовуються фігурні дужки, значення потрібно повернути явно:
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => {
number * 2;
});
console.log(doubled); // [undefined, undefined, undefined]Правильний варіант:
const doubled = numbers.map((number) => {
return number * 2;
});Або скорочений варіант:
const doubled = numbers.map((number) => number * 2);map замість filtermap не призначений для видалення елементів:
const numbers = [1, 2, 3, 4];
const result = numbers.map((number) => {
if (number % 2 === 0) {
return number;
}
});
console.log(result); // [undefined, 2, undefined, 4]Для вибору елементів використовуйте filter:
const result = numbers.filter((number) => number % 2 === 0);
console.log(result); // [2, 4]Такий код змінює початкові об’єкти:
const users = [
{ name: "Олена", score: 10 }
];
const updatedUsers = users.map((user) => {
user.score += 5;
return user;
});
console.log(users[0].score); // 15Безпечніше створити новий об’єкт:
const updatedUsers = users.map((user) => ({
...user,
score: user.score + 5
}));map змінить початковий масивconst numbers = [1, 2, 3];
numbers.map((number) => number * 2);
console.log(numbers); // [1, 2, 3]Результат потрібно зберегти або одразу передати далі:
const doubled = numbers.map((number) => number * 2);map використовується для перетворення кожного елемента масиву та створення нового масиву.
Основні правила:
callback викликається для кожного елемента;
результат callback стає елементом нового масиву;
початковий масив не змінюється;
кількість елементів зазвичай залишається такою самою;
для фільтрації використовуйте filter;
для побічних дій без нового масиву використовуйте forEach;
під час роботи з об’єктами створюйте копії, якщо потрібно уникнути мутації;
для асинхронних callback використовуйте Promise.all.
const products = [
{ name: "Книга", price: 300 },
{ name: "Зошит", price: 80 }
];
const productSummaries = products.map((product) => ({
name: product.name,
priceWithDiscount: product.price * 0.9
}));
console.log(productSummaries);
// [
// { name: "Книга", priceWithDiscount: 270 },
// { name: "Зошит", priceWithDiscount: 72 }
// ]