Psát o tom, že je to jazyk, který se vrací jako bumerang a v současné době zažívá své znovuzrození, je stejně zbytečné, jako to, že je to jazyk, který má asi nejsvětlejší budoucnost ze všech.
Díky bohu, že jsme se postupně dostali přes různé slepé uličky či uzavřeli jQuery, které splnilo svou historickou povinnost a odešlo do věčných lovišť. Již dávno jsou pryč časy, kdy většina vývojářů k javascriptu přistupovalo způsobem: google -> stackoverflow -> copy & paste.
Díky nové specifikaci (ES5 a ES6), jsme schopni k tomuto jazyku již přistupovat mnohem přímočařeji.
Dnešní ukázka se bude týkat práce s polem. V ukázce je použit typescript.
1. Představte si, že máte uživatele, který má následující vlastnosti:
interface User { readonly id: number; readonly firstName: string; readonly lastName: string; readonly roles: string[]; readonly countOfClicks: number; }
2. Nyní si vytvoříme pole uživatelů
const users: User[] = [ {id: 1, firstName: 'Ales', lastName: 'Dostal', roles: ['admin', 'operator', 'manager'], countOfClicks: 32}, {id: 2, firstName: 'Petr', lastName: 'Vomacka', roles: ['operator', 'manager'], countOfClicks: 43}, {id: 3, firstName: 'Martin', lastName: 'Novak', roles: ['manager'], countOfClicks: 0}, {id: 4, firstName: 'Petr', lastName: 'Novotny', roles: ['operator'], countOfClicks: 13}, {id: 5, firstName: 'Jan', lastName: 'Novak', roles: ['manager', 'superuser'], countOfClicks: 31}, {id: 6, firstName: 'Petr', lastName: 'Sulek', roles: ['manager', 'superuser'], countOfClicks: 18}, ];
Úkol 1: Celkový počet kliků
Prvním zadáním je celkový počet kliků, všech uživatelů.
Pokud bychom nepoužívali ES5 a arrow functions, tak by zápis vypadal následovně:
let countAll = 0; for (let i = 0; i < users.length; i++) { countAll += users[i].countOfClicks; } console.log('countAll: ', countAll);
V případě využití ES5 a arrow functions, lze dané zadání přepsat následovně:
const countAll = users.reduce((result, user) => (result + user.countOfClicks), 0); console.log('countAll: ', countAll);
Výsledek:
countAll: 137
Docela rozdíl, že? Pojdmě se podívat na další možnosti, které již budou využívat pouze ES5 a arrow functions. Nechceme přeci psát zastaralým stylem :)
Úkol 2: Průměrný počet kliků
const average = users.reduce((result, user, index, array) => { result += user.countOfClicks; if (index === array.length - 1) { return result / array.length; } return result; }, 0); console.log('average: ', average);
Výsledek:
average: 22.833333333333332
Úkol 3: Najdi všechny uživatele s jménem Petr
const petrUsers = users.filter((f) => f.firstName === 'Petr'); console.log('petrUsers: ', petrUsers);
Výsledek:
petrUsers: [ { id: 2, firstName: 'Petr', lastName: 'Vomacka', roles: [ 'operator', 'manager' ], countOfClicks: 43 }, { id: 4, firstName: 'Petr', lastName: 'Novotny', roles: [ 'operator' ], countOfClicks: 13 }, { id: 6, firstName: 'Petr', lastName: 'Sulek', roles: [ 'manager', 'superuser' ], countOfClicks: 18 } ]
Úkol 4: Pole ID uživatelů
const ids = users.map((user) => (user.id)); console.log('ids: ', ids);
Výsledek:
ids: [ 1, 2, 3, 4, 5, 6 ]
Úkol 5: Unikátní pole rolí
Výsledkem bude pole rolí, kde se žádná z rolí nebude opakovat:
const roles = users.reduce((result, user) => { result.push(...user.roles.filter((f) => result.indexOf(f) === -1)); return result; }, []); console.log('roles: ', roles);
Výsledek:
roles: ['admin', 'operator', 'manager', 'superuser']
Úkol 6: Pole jmen a počet výskytů
Výsledkem bude pole jmen a počet výskytů v poli uživatelů.
const uniqueFirstNameCount = users.reduce((result, user) => { result[user.firstName] = (result[user.firstName] || 0) + 1; return result; }, []); console.log('uniqueFirstNameCount: ', uniqueFirstNameCount);
Výsledek:
uniqueFirstNameCount: [Ales: 1, Petr: 3, Martin: 1, Jan: 1]
Závěr
Znalost využívání funkcí jako je map, reduce, filter, find či sort je jedna z klíčových věcí, kterou by programátor měl znát.
Díky tomu, že javascript je jazyk, který lze dnes využívat i na serveru, tak díky znalosti funkcí pro pole je možné tuto znalost aplikovat, například pro mongodb.
Pokud by někdo našel optimálnější způsob zápisu, daných úkolů, nechť se o ně podělí v komentáři.
Přál bych si, aby tyhle tři metody používalo více lidí. Takže díky za sepsání!
OdpovědětVymazatV návaznosti na výzvu v poslední větě přikládám, jak bych tyto úkoly vyřešil já. Neříkám, že je to tak lepší, jen pro porovnání ;)
1) Celkový počet kliků
```
const sum = (prev, next) => prev + next
const countAll = users
.map(({ countOfClicks }) => countOfClicks)
.reduce(sum)
```
Výhoda je, že `sum` je obecná znovupoužitelná metoda.
2) Průměrný počet kliků
```
const average = users
.map(({ countOfClicks }) => countOfClicks)
.reduce((prev, n, index) => (index * prev + n) / (index + 1))
```
Zde v reduce vždy předávám průměr předchozích čísel. Příjde mi to univerzálnější a dalo by se to použít např. s observables.
3) + 4) Udělal bych (samozřejmě) stejně, jen bych hodnotu získal z argumentu pomocí destructuringu `({ id }) => id`
5) Unikátní pole rolí
```
const flatten = (prev, next) => prev.concat(next)
const roles = new Set(users
.map(({ roles }) => roles)
.reduce(flatten)
)
console.log([...roles])
```
Unikátní hodnoty, skoro volají po Set :D
6) Pole jmen a počet výskytů
```
const updateMap = (updater) => (map, key) =>
map.set(key, updater(map.get(key)))
const addOne = (n = 0) => n + 1
const firstNameCounts = users
.map(({ firstName }) => firstName)
.reduce(updateMap(addOne), new Map())
console.log(firstNameCounts)
// -> Map(4) {"Ales" => 1, "Petr" => 3, "Martin" => 1, "Jan" => 1}
```
Jak se píše na stránce o Map na MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) jedno z kritérií pro použití Map místo objektu je: „Are keys usually unknown until run time?“ Tohle je přesně ten případ.
Ta konstrukce s `updateMap` se mi líbí, protože je jasné, co se kdy děje, a je to opět znovupoužitelné.
Koukám, že se nazachovalo formátování kódu :(
VymazatPokud řádek začíná tečnou, byl odsazený. Stejně tak je odsazený druhý řádek funkce `updateMap `.
Ahoj.
VymazatSkvěle přepsané.
I když se ti to nezformátovalo, tak čitelné to je.
Já jsem se držel víc při zemi, co se týče funkcionálního zápisu. Funkcionální přístup je tak mocný, že občas je to na úkor přehlednosti.
Vždycky hledám střední cestu. Srozumitelnost vs efektivní zápis.
Object destructuring jsem nepoužil záměrně, protože jsem na tuto oblast chtěl napsat článek. Ale souhlas, že se zde hodí :)