JavaScript 04 · JavaScript obecně
Pole I: map, filter a spol.
Indexy, map, filter, find, some, every, forEach a řetězení metod.
Načítám lekci…
JavaScript 04 · JavaScript obecně
Indexy, map, filter, find, some, every, forEach a řetězení metod.
Načítám lekci…
Pole je seřazená řada hodnot – jako vagóny vlaku nebo bedny na pásovém dopravníku. Každá má své pořadové číslo (index) a počítá se od nuly.
Představ si třídírnu ovoce s pásovým dopravníkem. Na pás položíš bednu jablek a podle toho, jaký stroj na konci stojí, dostaneš něco jiného:
map) – každé jablko projde strojem a vyjede oloupané. Kolik jablek vjelo, tolik jich vyjede.filter) – propustí jen některá jablka. Jablka se nemění, jen jich je míň.find) – zastaví pás u prvního jablka, které hledáš, a podá ti ho.some/every) – řekne jen „ano“ nebo „ne“: je tam aspoň jedno shnilé? Jsou všechna zralá?Všechny tyhle stroje fungují stejně: dostanou funkci (callback) a zavolají ji pro každou položku. Ty jen napíšeš, co se má stát s jednou položkou. V Reactu je to denní chleba – každý seznam na stránce vzniká přes map, každé vyhledávání přes filter.
const fruits = ['jablko', 'hruška', 'švestka']const empty = []const mixed = [1, 'text', true, { a: 1 }, [1, 2]] // pole může obsahovat cokolifruits.length // 3fruits[0] // 'jablko' – první položka má index 0fruits[2] // 'švestka' – poslední má index length - 1fruits[3] // undefined – mimo rozsah není chybafruits.at(-1) // 'švestka' – záporný index počítá od koncefruits.at(-2) // 'hruška'fruits.length === 0 // je pole prázdné?Array.isArray(fruits) // true – tak se pozná pole (typeof vrací 'object')
Nejčastější podoba dat v reálné aplikaci – a v Reactu taky:
const users = [{ id: 1, name: 'Jana', city: 'Praha' },{ id: 2, name: 'Petr', city: 'Brno' },]users[1].name // 'Petr'users[0].city // 'Praha'users.at(-1).id // 2
Array.from({ length: 3 }, (_, i) => i + 1) // [1, 2, 3] – pole o dané délceArray.from('ahoj') // ['a', 'h', 'o', 'j']'a,b,c'.split(',') // ['a', 'b', 'c'][...'ahoj'] // ['a', 'h', 'o', 'j']
const fruits = ['jablko', 'hruška', 'švestka']fruits.includes('hruška') // truefruits.includes('banán') // falsefruits.indexOf('švestka') // 2fruits.indexOf('banán') // -1 – „nenašel“
const fruits = ['jablko', 'hruška', 'švestka']// Klasický for – když potřebuješ index nebo přeskakovatfor (let i = 0; i < fruits.length; i++) {console.log(i, fruits[i])}// for…of – nejčitelnější, když chceš jen projít položkyfor (const fruit of fruits) {console.log(fruit)}// for…of s indexemfor (const [i, fruit] of fruits.entries()) {console.log(i, fruit)}// forEach – zavolá funkci pro každou položkufruits.forEach((fruit, i) => console.log(i, fruit))
| for / for…of | forEach | map | |
|---|---|---|---|
| Vrací | nic (je to příkaz) | undefined | nové pole |
| Jde přerušit (break)? | ano | ne | ne |
| Kdy | smyčka s break, await uvnitř | vedlejší efekt pro každou položku (log, uložení) | když chceš z pole udělat jiné pole |
map zavolá tvoji funkci pro každou položku a z jejích návratových hodnot složí nové pole stejné délky. Původní pole se nemění.
const numbers = [1, 2, 3, 4]numbers.map((n) => n * 2) // [2, 4, 6, 8]numbers.map((n) => n * n) // [1, 4, 9, 16]numbers.map((n) => `#${n}`) // ['#1', '#2', '#3', '#4']numbers.map((n) => n > 2) // [false, false, true, true]numbers.map(String) // ['1', '2', '3', '4'] – hotová funkce jako callbacknumbers // [1, 2, 3, 4] – beze změny
const users = [{ id: 1, first: 'Jana', last: 'Nováková', age: 31 },{ id: 2, first: 'Petr', last: 'Svoboda', age: 17 },]// Vytáhnout jednu vlastnostusers.map((u) => u.id) // [1, 2]// Spočítat něco novéhousers.map((u) => `${u.first} ${u.last}`) // ['Jana Nováková', 'Petr Svoboda']// Destrukturace přímo v parametruusers.map(({ first, age }) => `${first} (${age})`) // ['Jana (31)', 'Petr (17)']// Nový objekt s vybranými vlastnostmi – POZOR na kulaté závorkyusers.map((u) => ({ id: u.id, name: u.first })) // [{ id: 1, name: 'Jana' }, …]// Kopie s přidanou vlastností (původní objekty zůstanou)users.map((u) => ({ ...u, isAdult: u.age >= 18 }))
const fruits = ['jablko', 'hruška', 'švestka']fruits.map((fruit, i) => `${i + 1}. ${fruit}`) // ['1. jablko', '2. hruška', '3. švestka']fruits.map((_, i) => i) // [0, 1, 2] – _ = „tenhle parametr nepotřebuju“
filter zavolá funkci pro každou položku. Když funkce vrátí true (nebo cokoli pravdivého), položka projde do nového pole – celá a nezměněná.
const numbers = [5, 12, 8, 130, 44]numbers.filter((n) => n > 10) // [12, 130, 44]numbers.filter((n) => n % 2 === 0) // [12, 8, 130, 44] – sudánumbers.filter((n) => n > 1000) // [] – žádná shoda = prázdné pole, ne undefined
const products = [{ id: 1, name: 'Jablko', price: 12, inStock: true, category: 'ovoce' },{ id: 2, name: 'Hruška', price: 15, inStock: false, category: 'ovoce' },{ id: 3, name: 'Mrkev', price: 6, inStock: true, category: 'zelenina' },]products.filter((p) => p.inStock) // Jablko, Mrkevproducts.filter((p) => !p.inStock) // Hruškaproducts.filter((p) => p.category === 'ovoce') // Jablko, Hruškaproducts.filter((p) => p.price >= 10 && p.inStock) // Jablko// Odebrat položku podle id – „nech všechno KROMĚ“products.filter((p) => p.id !== 2) // Jablko, Mrkev// Vyhledáváníconst query = 'ja'products.filter((p) => p.name.toLowerCase().includes(query.toLowerCase())) // Jablko// Vyhodit prázdné hodnoty['a', '', null, 'b', undefined].filter(Boolean) // ['a', 'b']
const users = [{ id: 1, name: 'Jana', city: 'Praha' },{ id: 2, name: 'Petr', city: 'Brno' },{ id: 3, name: 'Eva', city: 'Brno' },]users.find((u) => u.id === 2) // { id: 2, name: 'Petr', city: 'Brno' } – objekt, ne poleusers.find((u) => u.city === 'Brno') // Petr – jen PRVNÍ shodausers.find((u) => u.id === 99) // undefinedusers.findIndex((u) => u.id === 3) // 2 – poziceusers.findIndex((u) => u.id === 99) // -1users.findLast((u) => u.city === 'Brno') // Eva – hledá od konce
| find | filter | |
|---|---|---|
| Vrací | jednu položku (nebo undefined) | vždy pole (i prázdné) |
| Zastaví se | u první shody | projde všechno |
| Typicky | detail podle id | seznam podle podmínky |
const products = [{ name: 'Jablko', price: 12, inStock: true },{ name: 'Hruška', price: 15, inStock: false },]products.some((p) => !p.inStock) // true – je aspoň jeden vyprodaný?products.some((p) => p.price > 100) // falseproducts.every((p) => p.price < 20) // true – jsou všechny levnější než 20?products.every((p) => p.inStock) // false// Typické použitíconst canCheckout = cart.every((item) => item.inStock)const hasErrors = fields.some((f) => f.error)
Protože map i filter vracejí pole, můžeš na výsledek rovnou zavolat další metodu. Čti to shora dolů jako postup v receptu:
const result = products.filter((p) => p.inStock) // 1. jen skladem.filter((p) => p.price < 20) // 2. jen levné.map((p) => p.name.toUpperCase()) // 3. jen jména velkými písmeny// Totéž s mezikroky – někdy čitelnějšíconst inStock = products.filter((p) => p.inStock)const cheap = inStock.filter((p) => p.price < 20)const names = cheap.map((p) => p.name.toUpperCase())
Co vidíš: Šest produktů (dva vyprodané), řada tlačítek s metodami a pod nimi kód, vysvětlení a výsledek. Zvýrazněné produkty jsou ty, které metoda „vzala“. reduce a toSorted jsou ochutnávka příští lekce.
Vyzkoušej:
Co z toho plyne: Než sáhneš po metodě, zeptej se: chci zpátky pole stejné délky (map), kratší pole (filter), jednu položku (find), nebo ano/ne (some/every)?
Načítám interaktivní část…
| Chci… | Metoda | Vrací |
|---|---|---|
| z každé položky udělat něco jiného | map | nové pole stejné délky |
| jen některé položky | filter | nové pole (kratší nebo stejné) |
| první položku, která splňuje podmínku | find | položku, nebo undefined |
| pozici první takové položky | findIndex | číslo, nebo -1 |
| vědět, jestli aspoň jedna splňuje | some | true / false |
| vědět, jestli všechny splňují | every | true / false |
| vědět, jestli pole obsahuje hodnotu | includes | true / false |
| pro každou položku něco udělat (bez výsledku) | forEach | undefined |
Jedno volání map a jedno volání filter – doplníš jen to, co vrací callback.
Zadání najdeš v komentářích v kódu níže – na začátku souboru a u míst označených TODO.
Načítám interaktivní část…
Osm dotazů nad seznamem úkolů. Metoda pole je u každého už napsaná – ty doplníš, co vrací callback: hodnotu z úkolu, nebo podmínku. Komentář u každého TODO říká, co má callback vrátit. Pod editorem uvidíš, které funkce už fungují.
Zadání najdeš v komentářích v kódu níže – na začátku souboru a u míst označených TODO.
Načítám interaktivní část…
arr.at(-1), mimo rozsah je undefined.includes/indexOf jen pro jednoduché hodnoty; objekty hledej přes some/find podle vlastnosti.return a ({ … }).!==.undefined – hlídej ji přes ?..true.