Moderní tvorba webových aplikací

O webu

Metoda reduce v JavaScriptu

Kdy (ne)použít metodu reduce v JavaScriptu. Praktické příklady a srovnání s alternativami.

6 minut

Metoda reduce umožňuje redukovat pole na jedinou hodnotu. Je to mocný nástroj, ale v praxi existuje téměř vždy čitelnější alternativa. Tento článek ukazuje, kdy reduce skutečně použít a kdy sáhnout po jiném řešení.

Základní syntaxe

pole.reduce((akumulator, hodnota, index, pole) => {
  return novyAkumulator;
}, pocatecniHodnota);

Přestože je počáteční hodnota volitelná, v praxi je téměř vždy lepší ji uvést. Zabráníte tím chování, které je v krajních případech překvapivé (například prázdné pole).

Proč se reduce nadužívá

Metoda reduce se v praxi používá mnohem častěji, než by bylo vhodné. Důvodů je několik:

  • Působí „funkcionálně“ — pochází z funkcionálního programování a přišla s vlnou FP spolu s map a filter, takže ji lidé automaticky považují za moderní přístup
  • Tutoriály — často ji prezentují jako „pokročilou techniku“, kterou by měl znát každý JS vývojář
  • One-liner syndrom — láká k zápisu všeho na jeden řádek, i když výsledek je nečitelný
  • Universálnost — pomocí reduce lze skutečně implementovat všechny ostatní array metody (map, filter, find, some, every, flat…), což vede k dojmu, že je to „správný“ nástroj na vše

Ve skutečnosti je reduce okrajový nástroj pro specifické případy. Pro většinu úloh existuje čitelnější alternativa.

Výhody reduce

Přesto má reduce několik legitimních výhod:

  • Výsledek jako const — nepotřebujete let proměnnou, kterou postupně měníte. To má tu výhodu, že nehrozí, že se dále v kódu omylem přepíše
  • Zapouzdřený stav — akumulátor neuniká do okolního scope
  • Jeden výraz — lze použít přímo v expression kontextu (přiřazení, return, ternární operátor)
  • Žádné mezivýsledky — na rozdíl od filter().map() nevytváří mezipole

Výkonnost: Samotný reduce je kvůli režii volání funkce o něco pomalejší než prostý for cyklus. Výhodu má při nahrazení řetězených metod (filter().map()), kde ušetří vytváření mezipole a druhý průchod. V praxi je rozdíl obvykle tak malý, že má větší smysl řešit čitelnost.

Kdy reduce nepoužívat

Ve většině případů existuje kratší a čitelnější alternativa:

Maximum a minimum

Pokud použijete reduce, vždy dejte počáteční hodnotu, ať se vám chování nerozpadne na prázdném poli.

const cisla = [3, 7, 2, 9, 1];

// S reduce
const max = cisla.reduce((a, b) => a > b ? a : b);

// Bez reduce — kratší a jasnější
const max = Math.max(...cisla);
const min = Math.min(...cisla);

Zploštění pole

const vnorene = [[1, 2], [3, 4], [5, 6]];

// S reduce
const ploche = vnorene.reduce((acc, arr) => acc.concat(arr), []);

// Bez reduce — kratší
const ploche = vnorene.flat();

Seskupování dat

const lide = [
  { jmeno: "Anna", vek: 25 },
  { jmeno: "Petr", vek: 30 },
  { jmeno: "Jana", vek: 25 }
];

// S reduce — 6 řádků
const podleVeku = lide.reduce((acc, osoba) => {
  const klic = osoba.vek;
  if (!acc[klic]) acc[klic] = [];
  acc[klic].push(osoba);
  return acc;
}, {});

// Bez reduce — 1 řádek (moderní prohlížeče)
const podleVeku = Object.groupBy(lide, o => o.vek);

Poznámka: Object.groupBy je relativně nová funkce, takže ji používejte jen tam, kde máte jistotu podpory v cílovém prostředí (nebo máte transpiling/polyfill).

Filtrování a mapování

Vyfiltruje sudá čísla a zdvojnásobí je — výsledek je [4, 8, 12].

const cisla = [1, 2, 3, 4, 5, 6];

// S reduce
const vysledek = cisla.reduce((acc, n) => {
  if (n % 2 === 0) acc.push(n * 2);
  return acc;
}, []);

// Bez reduce — čitelnější
const vysledek = cisla.filter(n => n % 2 === 0).map(n => n * 2);

Počítání výskytů

const ovoce = ["jablko", "banán", "jablko", "banán", "jablko"];

// S reduce
const pocty = ovoce.reduce((acc, o) => {
  acc[o] = (acc[o] || 0) + 1;
  return acc;
}, {});

// Bez reduce — podobná délka, ale přímočařejší
const pocty = {};
for (const o of ovoce) {
  pocty[o] = (pocty[o] || 0) + 1;
}

Kdy reduce skutečně použít

Součet čísel

const cisla = [1, 2, 3, 4, 5];

// S reduce
const soucet = cisla.reduce((acc, n) => acc + n, 0);

// Bez reduce
let soucet = 0;
for (const n of cisla) soucet += n;

Výsledek s reduce je const a pomocná proměnná neuniká do scope.

Skládání funkcí (compose/pipe)

const pricti5 = x => x + 5;
const vynasob2 = x => x * 2;
const odecti3 = x => x - 3;

// S reduce
const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);

// pipe: funkce se volají zleva doprava
pipe(pricti5, vynasob2, odecti3)(10);    // ((10 + 5) * 2) - 3 = 27

// compose: funkce se volají zprava doleva
compose(odecti3, vynasob2, pricti5)(10); // ((10 + 5) * 2) - 3 = 27

// Bez reduce — vnořené volání
odecti3(vynasob2(pricti5(10)));          // ((10 + 5) * 2) - 3 = 27

// Bez reduce — cyklem
const pipe = (...fns) => x => {
  let result = x;
  for (const fn of fns) result = fn(result);
  return result;
};

Vnořené volání je při více funkcích nečitelné. Cyklus funguje, ale reduce je zde nejelegantnější.

Shrnutí

  • Nepoužívejte reduce pro jednoduché operace — map, filter, flat, Math.max bývají čitelnější
  • Používejte reduce pro součty a skládání funkcí (pipe/compose)
  • Vždy uvádějte počáteční hodnotu — bez ní reduce na prázdném poli vyhodí TypeError

Odkazy

Související články

Jak vkládat 3D objekty na web pomocí Three.js

Které formáty použít, jak vytvářet modely pomocí AI a kdy raději použít obrázek nebo video.

15 minut

Detekce otevření DevTools

Jak zjistit, že se na stránce otevřely vývojářské nástroje.

13 minut

JavaScript null a undefined

Rozdíly mezi null a undefined v JavaScriptu, kdy je používat a jak se vyhnout běžným chybám.

12 minut

Sleep v JavaScriptu

Jak implementovat sleep/delay funkcionalitu v JavaScriptu pomocí Promise a async/await

6 minut

Novinky e-mailem

Když budu mít něco opravdu zajímavého, můžu vám to poslat e-mailem

Přidej se k 500+ čtenářům
Jen kvalitní obsah
Žádný spam

Web jecas.cz píše Bohumil Jahoda, kontakt
Seznam všech článků
2013–2025