Skip to main content

Методи масиву vs цикли

1. Коротко: у чому суть

Методи масивів (map, filter, forEach, reduce і т.д.) - це абстракції над циклами, написані всередині рушія JavaScript. Вони зручніші, коротші й зрозуміліші, але мають додаткові накладні витрати, через що можуть бути повільнішими за прості цикли (for, for…of, while) - особливо на великих масивах.


2. Що відбувається "під капотом"

Коли ти пишеш:

javascript
arr.map(x => x * 2);

рушій робить приблизно таке:

  1. Перевіряє, що arr дійсно масив.
  2. Створює новий масив для результатів.
  3. На кожній ітерації:
  • викликає callback-функцію;
  • передає їй три аргументи (element, index, array);
  • зберігає результат у новий масив.
  1. Повертає підсумковий масив.

Це купа кроків, які додають накладні витрати, порівняно зі звичайним for-циклом, де ти просто виконуєш інструкції без обгорток і перевірок.


3. Чому саме повільніше

ПричинаЩо відбувається
Callback-функціяНа кожній ітерації викликається нова функція -> зайві виклики стека
Створення нового масивуmap, filter, slice, concat створюють копії (дод. пам'ять)
Перевірки й контекстМетод проходить валідації (довжина, holes, прототип, тип)
Неоптимізовані замиканняЯкщо колбек захоплює зовнішні змінні - ще більше накладних витрат
Функціональні принципиЦі методи "чисті" і не мутують дані -> потрібно більше алокацій
Цикли простіше оптимізувати JIT-компіляторуРушій (V8, SpiderMonkey) швидше оптимізує "голий" for

4. Приклад порівняння

javascript
const arr = Array.from({ length: 1_000_000 }, (_, i) => i); // map console.time('map'); const doubled1 = arr.map(x => x * 2); console.timeEnd('map'); // for console.time('for'); const doubled2 = new Array(arr.length); for (let i = 0; i < arr.length; i++) { doubled2[i] = arr[i] * 2; } console.timeEnd('for');

На більшості рушіїв результат буде приблизно такий:

javascript
map: 30-60 ms for: 10-20 ms

Різниця невелика на малих даних, але при мільйонах елементів - у 2-5 разів швидше з for.


5. Чому це особливо помітно в "гарячих" ділянках коду

Якщо цикл виконується мільйони разів (рендеринг, сортування, агрегації даних, парсинг) - накладні витрати колбеків починають "коштувати дорого".

У таких місцях:

  • кожен виклик колбека = новий запис у call stack;
  • зайві алокації = більше роботи GC (garbage collector);
  • дод. аргументи (index, array) -> більше об'єктів у пам'яті.

6. Коли це не має значення

Для більшості бізнес-задач (списки, фільтри, маппінг до 10k елементів):

  • різниця між for і map - частки мілісекунди;
  • читабельність і чистота коду важливіші.

Тому в React/Vue-коді використовують .map() для JSX, бо це декларативно й зрозуміло:

javascript
{items.map(item => <Card key={item.id} {...item} />)}

Але якщо у тебе масив на мільйони елементів або цикл у "гарячому місці" (рендеринг, обробка бінарних даних, canvas, парсер) - краще використовувати:

javascript
for (let i = 0; i < n; i++) ...

7. Що реально швидше (за порядком)

ЦиклШвидкістьОсобливості
for (let i = 0; i < n; i++)НайшвидшийНемає перевірок, inline, передбачуваний
for...ofШвидкий, але з ітераторомТрохи накладних витрат
whileПриблизно так самоМайже як for, залежить від рушія
forEach()Повільніший (callback)Не повертає новий масив
map()Повільніший, створює новий масив
filter(), reduce()Ще повільнішеАлокації, дод. операції

8. Як прискорити методи масивів

МетодОптимізація
.map()Використовувати всередині чисту стрілочну функцію без зовнішніх замикань
.filter()Не використовувати ланцюжки .map().filter().reduce(), а об'єднувати в один цикл
.reduce()Для складних операцій - винести накопичення в for
.forEach()Заміняти на for або for...of у "гарячому" коді
.concat() / spread ([...a, ...b])Замінити на push.apply() або цикл при великих масивах

9. Коротке резюме

ПричинаЧому повільніше
Callback-функціїстворюють дод. виклики й контекст
Новий масиввиділяється нова пам'ять
Валідації та ітераціявбудовані перевірки й протоколи
GC-навантаженнястворюються тимчасові об'єкти
Цикли примітивнішілегше оптимізувати JIT-компілятору

Висновок:

  • Для задач, критичних за продуктивністю -> for.
  • Для зрозумілого, декларативного коду -> map, filter, reduce.

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

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

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