03.16 Higher-order Functions
Výuka
Proč Higher-order Functions?
„Existují dva způsoby konstruování softwarového návrhu: jeden je udělat ho natolik jednoduchý, že zřejmě nemá žádné nedostatky, a druhý je udělat ho natolik složitý, že nemá žádné zřejmé nedostatky." — C.A.R. Hoare
Higher-order functions (funkce vyššího řádu) jsou funkce, které:
- Přijímají jiné funkce jako argumenty, nebo
- Vrací funkce jako výsledek
Proč to potřebujeme?
- Abstrakce akcí - Ne jen abstrakce hodnot, ale abstrakce celých akcí
- Znovupoužitelnost - Napsat obecnou logiku jednou, použít s různými akcemi
- Funkcionální programování - Pracovat s funkcemi jako s "občany první třídy"
- Čistší kód - Méně opakování, více expresivity
Představ si to jako: Tovární linku. Místo abys měl speciální stroj na každý produkt, máš univerzální stroj, kterému řekneš "jak" má pracovat. Můžeš mu předat různé "návody" (funkce) a stejný stroj vytvoří různé produkty.
Jak to funguje?
1. Funkce je hodnota (jako číslo nebo text)
2. Funkce může přijmout jinou funkci jako parametr
3. Funkce může vytvořit a vrátit novou funkci
4. Výsledná funkce "pamatuje" prostředí, ve kterém vznikla (closure)
Klíčové koncepty
- Higher-order function - funkce pracující s jinými funkcemi
- First-class functions - funkce jsou hodnoty jako jakékoli jiné
- Abstrakce - zabalit složitost do pojmenovaného konceptu
- Funkce vracející funkci - factory pattern pro vytváření specializovaných funkcí
- Built-in HOF -
map,filter,reduce,forEach- vestavěné higher-order funkce na polích
JavaScript
Příklad 1: Funkce přijímající funkci (nejjednodušší HOF)
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, console.log);
// → 0
// → 1
// → 2
Co se stalo?
repeatje higher-order function - přijímá funkciactionjako parametr- Zavoláme
repeat(3, console.log)- předali jsme funkciconsole.log repeatzavoláconsole.logtřikrát s hodnotami 0, 1, 2
Proč je to užitečné? Abstrahovali jsme "opakování N-krát" - obsah akce je flexibilní!
Příklad 2: Funkce vracející funkci
function greaterThan(n) {
return function(m) {
return m > n;
};
}
const greaterThan10 = greaterThan(10);
console.log(greaterThan10(11)); // → true
console.log(greaterThan10(9)); // → false
Co se stalo?
greaterThan(10)vytvoří a vrátí novou funkci- Tato funkce "pamatuje"
n = 10(closure!) greaterThan10je funkce, která testuje, zda je číslo > 10- Můžeme vytvořit různé verze:
greaterThan5,greaterThan100, atd.
Příklad 3: Praktický příklad - noisy (logging wrapper)
function noisy(f) {
return function(...args) {
console.log("Volání s argumenty:", args);
const result = f(...args);
console.log("Vrácená hodnota:", result);
return result;
};
}
const noisyMin = noisy(Math.min);
noisyMin(3, 2, 1);
// → Volání s argumenty: [3, 2, 1]
// → Vrácená hodnota: 1
Co se stalo?
noisyje wrapper - obaluje jinou funkci a přidává logování- Vrací novou funkci, která:
- Zaloguje argumenty
- Zavolá původní funkci
- Zaloguje výsledek
- Vrátí výsledek
- Můžeš "obalit" jakoukoliv funkci!
Příklad 4: Array.map - transformace pole
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(function(n) {
return n * 2;
});
console.log(doubled);
// → [2, 4, 6, 8]
// Stejné s arrow funkcí (stručnější)
const tripled = numbers.map(n => n * 3);
console.log(tripled);
// → [3, 6, 9, 12]
Co se stalo?
mapje vestavěná higher-order funkce na polích- Přijímá funkci, která transformuje každý prvek
- Vytváří nové pole (nemění původní)
- Je to čistá funkce - žádné vedlejší efekty
Příklad 5: Array.filter - filtrování pole
const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = numbers.filter(function(n) {
return n % 2 === 0;
});
console.log(evenNumbers);
// → [2, 4, 6]
// S arrow funkcí
const oddNumbers = numbers.filter(n => n % 2 === 1);
console.log(oddNumbers);
// → [1, 3, 5]
Co se stalo?
filterje další vestavěná higher-order funkce- Přijímá funkci (test), která vrací
true/false - Vytváří nové pole obsahující pouze prvky, které prošly testem
Příklad 6: Kombinace map a filter (funkcionální pipeline)
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 17 },
{ name: "Charlie", age: 30 },
{ name: "Diana", age: 16 }
];
// Získat jména dospělých uživatelů
const adultNames = users
.filter(user => user.age >= 18)
.map(user => user.name);
console.log(adultNames);
// → ["Alice", "Charlie"]
Co se stalo?
filtervytvoří pole pouze s dospělými (věk >= 18)maptransformuje pole objektů na pole jmen- Výsledek: pole jmen dospělých uživatelů
Krása: Čitelný, deklarativní kód - říkáš "co chceš", ne "jak to udělat"
TypeScript
TypeScript přidává typové anotace pro higher-order funkce - můžeš specifikovat typy vstupních i výstupních funkcí.
Stejné příklady s typy
// Funkce přijímající funkci
function repeat(n: number, action: (i: number) => void): void {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, (i) => console.log(i));
// Funkce vracející funkci
function greaterThan(n: number): (m: number) => boolean {
return (m: number) => m > n;
}
const greaterThan10 = greaterThan(10);
console.log(greaterThan10(11)); // → true
// Typovaný map
const numbers: number[] = [1, 2, 3, 4];
const doubled: number[] = numbers.map((n: number): number => n * 2);
// Typovaný filter
interface User {
name: string;
age: number;
}
const users: User[] = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 17 }
];
const adults: User[] = users.filter((user: User): boolean => user.age >= 18);
const adultNames: string[] = adults.map((user: User): string => user.name);
TypeScript přidává:
- ✅ Kontrolu typů - editor zkontroluje, že funkce vrací správný typ
- ✅ IntelliSense - automatické návrhy a nápověda pro parametry
- ✅ Bezpečnost - nemůžeš omylem předat nekompatibilní funkci
- ✅ Dokumentaci v kódu - typové signatury jsou živá dokumentace
Rozdíl JS vs TS
JavaScript:
- Higher-order funkce fungují bez typů
- Flexibilnější, ale méně bezpečné
- Chyby zjistíš až při běhu programu
- Můžeš omylem předat funkci s nesprávným podpisem
TypeScript:
- Higher-order funkce mají jasné typové signatury
- TypeScript zkontroluje, že funkce sedí
- Chyby odhalíš už při psaní kódu
- Editor ti pomůže s parametry a návratovými hodnotami
// JavaScript - projde, ale způsobí problém
function map(array, transform) {
return array.map(transform);
}
const result = map([1, 2, 3], (x) => x.toUpperCase()); // Runtime error!
// TypeScript - editor tě upozorní
function map<T, U>(array: T[], transform: (item: T) => U): U[] {
return array.map(transform);
}
const result = map([1, 2, 3], (x) => x.toUpperCase());
// ❌ Error: Property 'toUpperCase' does not exist on type 'number'
Tip
💡 Používej vestavěné HOF (map, filter, reduce) místo cyklů:
// ❌ Imperativní styl - jak to udělat (cyklus)
const numbers = [1, 2, 3, 4];
const doubled = [];
for (let i = 0; i < numbers.length; i++) {
doubled.push(numbers[i] * 2);
}
// ✅ Deklarativní styl - co chceš (map)
const doubled = numbers.map(n => n * 2);
💡 Chainování (řetězení) HOF je čitelné:
// ✅ Čitelný funkcionální pipeline
const result = data
.filter(x => x.active)
.map(x => x.name)
.sort();
// ⚠️ Pozor na výkon - každý krok vytvoří nové pole
// Pro velká data zvažte reduce nebo for-loop
💡 Arrow funkce jsou přirozenější pro HOF:
// ❌ Verbose - anonymní function
numbers.map(function(n) { return n * 2; });
// ✅ Stručné - arrow funkce
numbers.map(n => n * 2);
// ✅ Ještě stručnější - implicitní return
numbers.filter(n => n > 10).map(n => n * 2);
Kvíz
Co je výsledek tohoto kódu?
function makeMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
console.log(double(5) + triple(4));
❌ - Chybný výpočet
✅ - double(5) vrátí 5 * 2 = 10, triple(4) vrátí 4 * 3 = 12, celkem 10 + 12 = 22
❌ - To je jen výsledek double(5)
❌ - To je jen výsledek triple(4)
Důležité: Každá vrácená funkce "pamatuje" svůj vlastní factor díky closure!
Důležité: Každá vrácená funkce "pamatuje" svůj vlastní factor díky closure!
🎯 Závěrečný projekt
Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.
Zobrazit podrobnosti projektu →Informace o seriálu
Obtížnost
Délka
Cca 480 minut
Počet videí
8 videí + projekty
Certifikát
Po dokončení obdržíte certifikát
Lekce v této sekci
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě