Skip to main content

Яка різниця між Map і foreach в Array

map повертає новий масив з трансформованими значеннями; forEach запускає функцію на кожному елементі і повертає undefined.

Теорія

TL;DR

  • map як ксерокс з фільтром: отримуєш новий стос аркушів, оригінал не змінився
  • forEach як маркер: позначає щось на місці і нічого не повертає
  • Головна різниця: map повертає новий масив, forEach повертає undefined
  • Потрібен новий масив? map. Просто логування або зовнішні зміни? forEach
  • Після forEach не можна будувати ланцюжок методів; після map можна: .filter(), .reduce()

Швидкий приклад

javascript
const nums = [1, 2, 3]; // map повертає новий масив const doubled = nums.map(n => n * 2); console.log(doubled); // [2, 4, 6] console.log(nums); // [1, 2, 3] - без змін // forEach повертає undefined const result = nums.forEach(n => n * 2); console.log(result); // undefined

Обидва методи обходять кожен елемент. map збирає повернені значення колбеку в новий масив. forEach їх ігнорує.

Ключова різниця

map будує і повертає новий масив тієї ж довжини, де кожна позиція містить те, що повернув колбек. Оригінальний масив залишається незмінним. forEach запускає колбек суто для побічних ефектів, ігнорує повернене значення і завжди повертає undefined. Ця одна різниця визначає все. Плутанина між цими двома методами одна з найчастіших речей у код-рев'ю з джунами.

Коли що використовувати

  • Трансформувати дані для відображення (форматувати імена, конвертувати одиниці, змінити структуру об'єктів) → map
  • Логувати або дебажити вміст масиву → forEach
  • Будувати ланцюжок .map().filter().reduce()map
  • Додавати елементи в зовнішній масив або робити API-виклики в циклі → forEach
  • Рендерити JSX-списки в React → map (forEach повертає undefined і зламає рендер)

Порівняльна таблиця

АспектmapforEach
ПовертаєНовий масивundefined
Оригінальний масивНе змінюєтьсяНе змінюється (якщо колбек не мутує)
Ланцюжок методівТакНі
Використовують дляТрансформаційПобічних ефектів
ШвидкістьТрохи повільніше (виділяє пам'ять)Трохи швидше (без виділення пам'яті)

Як це працює всередині

Обидва методи перебирають елементи масиву і викликають колбек з аргументами (value, index, array). Різниця в тому, що відбувається з поверненим значенням. map заздалегідь виділяє новий масив тієї ж довжини і записує кожен результат на відповідну позицію. forEach викидає кожне повернене значення і виходить з undefined.

Типові помилки

Очікувати від forEach повернення масиву:

javascript
const doubled = [1, 2, 3].forEach(n => n * 2); console.log(doubled); // undefined, а не [2, 4, 6]

Рішення: використовуй map.

Ланцюжок після forEach:

javascript
[1, 2, 3].forEach(x => x * 2).filter(x => x > 2); // TypeError: Cannot read properties of undefined

Рішення: спочатку map, потім ланцюжок.

Мутація оригіналу всередині map:

javascript
const arr = [1, 2, 3]; arr.map((n, i) => { arr[i] = n * 2; }); // мутує arr напряму

map не захищає від мутацій. Якщо мутуєш всередині нього, це не той інструмент. map призначений для повернення нових значень, не для зміни оригіналу.

Використання map суто для побічних ефектів:

javascript
users.map(user => console.log(user.name)); // виділяє масив, якого ніхто не використовує

Рішення: users.forEach(user => console.log(user.name)).

Де зустрічається в реальних проектах

  • React: users.map(user => <UserCard key={user.id} user={user} />) - рендер списків
  • Redux: state.items.map(item => ({ ...item, isNew: true })) - іммутабельне оновлення стану
  • Express: req.body.users.map(user => user.id) - витягнути ID перед запитом до БД
  • Node.js: data.forEach(chunk => stream.write(chunk)) - запис без збору результатів

Питання на співбесіді

Q: Що повертає forEach?
A: Завжди undefined. Повернене значення колбеку повністю ігнорується.

Q: Чи можна мутувати оригінальний масив всередині map?
A: Технічно так, але не варто. map призначений для повернення нових значень. Якщо потрібна мутація, використовуй звичайний цикл for.

Q: Коли forEach швидший за map?
A: Завжди трохи швидший, бо не виділяє пам'ять під новий масив. Різниця помітна лише на дуже великих масивах.

Q: Чому map працює в рендері React-компонента, а forEach ні?
A: React очікує масив JSX-елементів. map повертає цей масив. forEach повертає undefined, і React не знає що з ним робити.

Q: Реалізуй map через forEach.
A: const myMap = (arr, fn) => { const result = []; arr.forEach((item, i) => { result[i] = fn(item, i, arr); }); return result; };

Приклади

Трансформація даних з API

Типовий сценарій: отримуємо сирі об'єкти з API і потрібна інша структура перед передачею в компонент.

javascript
const users = [ { id: 1, firstName: 'Anna', lastName: 'Smith' }, { id: 2, firstName: 'Bob', lastName: 'Jones' }, ]; // map будує новий масив з потрібною структурою const displayNames = users.map(user => ({ id: user.id, fullName: `${user.firstName} ${user.lastName}`, })); console.log(displayNames); // [{ id: 1, fullName: 'Anna Smith' }, { id: 2, fullName: 'Bob Jones' }] console.log(users); // оригінал не змінився

map тут правильний вибір, бо потрібен новий масив для компонента. forEach змусив би оголосити зовнішній масив і робити push вручну: більше коду, той самий результат.

Побічні ефекти з forEach

javascript
const orders = [ { id: 101, total: 49.99, status: 'pending' }, { id: 102, total: 120.0, status: 'shipped' }, ]; // forEach: виводимо кожне замовлення, новий масив не потрібен orders.forEach(order => { console.log(`Order #${order.id}: $${order.total} (${order.status})`); }); // Умовний побічний ефект для кожного елемента orders.forEach(order => { if (order.status === 'pending') { sendReminderEmail(order.id); } });

Повернене значення тут не потрібне. map теж спрацює, але виділить масив із undefined, якого ніхто не використовує.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?