Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Яка різниця між Map і foreach в Array». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**map і forEach** - `map` трансформує кожен елемент і повертає новий масив тієї ж довжини; `forEach` запускає колбек для побічних ефектів і повертає `undefined`. ```js [1, 2, 3].map(n => n * 2); // [2, 4, 6] [1, 2, 3].forEach(n => n * 2); // undefined ``` **Головне:** потрібен новий масив → `map`; потрібен лише побічний ефект → `forEach`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`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` і зламає рендер) ### Порівняльна таблиця | Аспект | `map` | `forEach` | |---|---|---| | **Повертає** | Новий масив | `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`, якого ніхто не використовує.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.