5

Knihovny a vlastní funkce

Ukážeme si jak v JavaScriptu používat knihovny a naučíme se vytvářet vlastní funkce.

Jak už jsme viděli do této chvíle, jazyk JavaScript nabízí spoustu funkcí a metod, které jsou připravené pro všemožné účely. Máme funkce na práci s řetězci, na práci s DOMem, na matematické výpočty, na vstup a výstup a tak dále. Webové stránky jsou však neskutečně bohatý svět plný tolika možností a problémů, že jazyk JavaScript nikdy nemůže obsáhnout všechny funkce, které budeme při vývoji potřebovat. Zde ke slovu přichází takzvané knihovny libraries .

Knihovny

Knihovna je v podstatě jakýsi balíček funkcí, které se týkají nějaké konkrétní oblasti. Máme knihovny na

  • práci s datumem a časem,
  • stahování dat ze serveru,
  • ověřování vstupu od uživatele,
  • práci s mapami,
  • zpracování dat,
  • spouštění animací,
  • psaní her
  • a stovky dalších možností.

Různých knihoven se na internetu nachází tísíce a tísíce. Pokud během vývoje narazíte na nějaký problém, který potřebujete ve svém program vyřešit, je obrovská šance, že tentýž problém už někdo řešil před vámi a vyrobil na jeho řešení knihovnu. Často tedy stačí šikovně pogooglovat, najít tu správnou knihovnu a máte vystaráno.

Kontrola vstupu

Jeden z velmi častých problémů, které při vývoji potkáme, je kontrola vstupu od uživatele. Téměř každá větší stránka umožňuje přihlašování, a tak často musíme vytvořit nějaký formulář, kam uživatel zadává svůj e-mail. Jak ale poznáme, že uživatel do políčka pro e-mail zadal opravdu e-mail a ne nějaký nesmysl?

Zkontrolovat správný formát e-mailu v žádném případě není jednoduchá úloha. Rozhodně nastačí zkontrolovat, že obsahuje zavináč. Na wikipedii si můžete pro zajímavost přečíst, co všechno se považuje za validní e-mail a co naopak ne.

Zároveň ověřování e-mailu je tak častý programátorský úkon, že na to jistě musí existovat knihovna. My použíjeme knihovnu, která se jmenuje validator.js.

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/validator/13.5.2/validator.min.js"></script>
  <title>Moje stránka</title>
</head>

Knihovnu do naší stránky přidáme tak, že její adresu vložíme do hlavičky stránky pomocí tagu script. Každá knihovna má svoje pravidla fungování, která vyčteme z dokumentace. Knihovna validator.js nám ve stránce vytvoří objekt validator, který má mnoho užitečných metod, mezi nimi i metodu isEmail, která umí ověřit, zda je zadaný řetězec platný e-mail. Tuto metodu můžeme použít ve svém JavaScriptovém programu nebo si ji vyzkoušet rovnou v konzoli, když naši stránku otevřeme v prohlížeči.

> validator.isEmail('pepa.novak@seznam.cz')
true
> validator.isEmail('žbrblymrmly@prdy.com')
true
> validator.isEmail('martin@home')
false
> validator.isEmail('C5dMFFegdK4RX&iL')
false

Knihovna validator.js má desítky ověřovacích funkcí pro mnoho různých situací. Mezi nimi například funkci pro ověřování mobilních čísel pro různé země.

> validator.isMobilePhone('723 313 256', 'cs-CZ')
true
> validator.isMobilePhone('723 313 25', 'cs-CZ')
false

Mezi další užitečné funkce mohou patřit například

  • isCreditCard pro ověření čísla platební karty,
  • isPassportNumber pro oveření čísla pasu pro danou zemi,
  • isPostalCode pro ověření PSČ dle dané země.

Pro kompletní výčet všch funkcí nahlédněte do dokumentace knihovny.

Práce s datem a časem

Práce datem a časem je velmi častým úkolem v mnoha různých aplikacích. Zároveň je to jeden z nejtěžších programovacích problémů, protože datum a čas se řídí neuvěřitelně složitými pravidly, která mimo mnohé další zahrnují

  • fakt, že každý měsíc má jiný počet dní,
  • přestupné roky,
  • časové zóny,
  • letní a zimní čas v různých zemích,
  • různé kalendáři v různých zemích,
  • různé formáty zápisu data a času v různých zemích,
  • a tak dále.

Z toho všecho je jasné, že na práci s datem a časem budeme potřebovat nějakou knihovnu. Těch na internetu existuje vícero. My si vyzkoušíme knihovnu s názvem dayjs. Do naší stránky ji vložíme následujícím skriptem.

<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.4/dayjs.min.js" ></script>

Knihovna dayjs toho umí opravdu hodně, například

  • formátovat a parsovat datum i čas v různých formátech,
  • manipulace jako přidat den, ubrat dva týdny apod.,
  • porovnávat, který datum je dřív nebo později.

My si zde vyzkoušíme pouze pár základních věci. Aktuální datum a čas získáme zavoláním funkce dayjs.

const now = dayjs();

Toto datum pak můžeme vypsat do konzole v námi zvoleném formátu.

console.log(now.format('MM.DD.YYYY'));

Můžeme také zcela konkrétní datum vyrobit, například

const stedryDen = dayjs('2021-12-24')

Pomocí metody isAfter pak můžeme vyzkoušet, jestli už jsme propásli Štědrý den 2021 nebo nás teprve čeká.

const stedryDen = dayjs('2021-12-24')
const dnes = dayjs();

if (dnes.isAfter(stedryDen)) {
  console.log('Musíš počkat na příští rok');
} else {
  console.log('Už brzy přijde Ježíšek!');
}  

Pro ty, kdo se chtějí o knihovně dayjs dozvědět více, přikládáme opět odkaz na dokumentaci.

Cvičení: Knihovny

1

Kreditní karta

to dáš
  1. Vytvořte prázdnou stránku, do které vložte knihovnu validator.js a svůj JavaScript index.js.
  2. Otevřete stránku v prohlížeči a pomocí metody validator.isEmail ověřte svoji e-mailovou adresu. Výsledek ověření vypište do konzole.
  3. Pokud máte po ruce svoji platební kartu, ověřte, že má platné číslo pomocí metody isCreditCard.
  4. Do těla stránky vložte prázdný odstavec, který bude zobrazovat zprávu pro uživetele.
    <p id="msg" class="msg"></p>
    
  5. Pomocí funkce prompt požádejte uživatele o jeho e-mail. V případě, že jde o platný e-mail, zobrazte v připraveném odstavci zprávu “E-mail v pořádku”. V opačném případě zobrazte “Neplatný e-mail”.
  6. Pokud je e-mail platný, přidejte zároveň na odstavec CSS třídu msg--valid. V opačném případě použijte třídu msg--invalid. Přidejte do stránky soubor style.css a třídy nastylujte například tak, že msg--valid bude mí zelené pozadí a msg--invalid naopak červené.
2

Nouzový stav

to dáš

Podívejte se na stránku skonciluznouzovystav.cz. Podle toho, v jakém období toto zadání čtete, se dozvíte, zda již skončil nouzový stav spojený s pandemií COVID-19 či nikoliv. Stránka zobrazuje obyčejné ANO či NE a krátkou zprávu. Podobných stránek lze na internetu najít vícero. Například

Vytvořte podobnou stránku s vaším vlastním tématem.

  1. Vytvořte prázdnou stránku, do které vložte knihovnu dayjs.
  2. Vyberte si nějakou budoucí událost, jejíž datum je pevně určeno. Za pomoci knihovny dayjs vytvořte stránku zobrazující velké ANO nebo NE případně krátkou zprávu podle toho, zda už událost nastala či nikoliv.
  3. Publikuje vaši stránku na GitHub pages.

Vlastní funkce

Funkce jsou jednou z nejdůležitějších součástí programování. Všimněte si, jak často vaše programy sestávají z volání různých funkcí. Ve všech programovacích jazycích je již od začátku mnoho funkcí rovnou k dispozici. Často ale potřebujeme funkci, která dělá něco specifického, důležitého pouze pro náš program. V takovém případě nám nezbývá, než si takovou funkci naprogramovat samí.

Představme si například, že vyměřujeme pozemek a chceme spočítat plochu pozemku, který má tvar pravoúhlého trojúhelníka o šířce width a výšce height jako na obrázku.

Pozemek

Naše funkce tedy bude mít dva vstupy - šířku a výšku. Ze školy si pamatujeme, že plochu prvoúhlého trojúhelníka spočítáme tak, že vynásobíme šířku výškou a výsledek vydělíme dvěma. Už tedy víme, co má funkce dělat a zbývá nám tento postup zapsat v JavaScritpu.

(width, height) => {
  return (width * height) / 2;
};

Zápis funkce se dělí na definici vstupů inputs (před šipkou) a tělo body (za šipkou). Jako vstupy v kulatých závorkách vidíme dvě slova width a height. To jsou speciální proměnné, kterým říkáme parametry parameters .

Ve složených závorkách pak máme takzvané tělo funkce. To obsahuje kód, který se má vykonat, když funkci zavoláme. Úkolem naší funkce je vrátit nějaký výsledek. Speciální slovíčko return proto říká, co má být výsledkem naší funkce.

Zbývá ukázat, jak naší funkci zavoláme. Zde přichází jedno z nejdůležitějších uvědomění, které v JavaScriptu kdy zažijete.

Funkce je hodnota, podobně jako číslo nebo řetězec!

Funkci můžeme uložit do proměnné stejně jako každou jinou hodnotu. Uložením do proměnné tak funkci dáme jméno. Všimněte si, že jde o stejný postup jako s jakoukoliv jinou hodnotou.

const age = 25;
const user = 'robert';
const married = false;
const element = document.querySelector('.card');
const landArea = (width, height) => {
  return (width * height) / 2;
};

Jakmile máme funkci takto hezky uloženou v proměnné, můžeme jí zavolat známým způsobem.

landArea(5, 3);

Jakmile funkci takto zavoláme, například s hodnotami 5 a 3, JavaScript tyto hodnoty uloží do parametrů width a height a v těle funkce pak parametry použjeme jako normální proměnné pro náš výpočet.

Složitější funkce

Ne každá funkce je tak přímočará, jako výpočet obsahu. Často se stane, že potřebujeme ve funkci provést nějaké rozhodování, výpočet sestávají z více kroků apod. Mějme například funkci, která rozhodne, zda máme dostatečně bezpečné heslo. Heslo budeme považovat za bezpečné, pokud je delší než 12 znkaů. V takovéto funkci tedy potřebujeme použít podmínky. Tělo funkce proto bude obsahovat více příkazů, které se nám už nevejdou na jeden řádek. V takovém případě bude tělo funkce blok kódu podobně jako to už známe u podmínek.

const isSafe = (password) => {
  if (password.length >= 12) {
    return true;
  } else {
    return false;
  }
};

Všimněte si, že v této funkci máme vícero slovíček return, protože funkce v různých situacích vrací různé výsledky. Ve chvíli, kdy JavaScript runtime při vykonává funkce narazí na return, vykonávání funkce se ukončí a program se vrací na místo, odkud byla funkce volána. Vrácená hodnota pak bude na tomto místě výsledkem naší funkce. Ten si pak můžeme uložit třeba do proměné.

const result = isSafe('popokatepetl');

Vzhledem k tomu, že příkazem return se průběh funkce ukončuje, můžeme funkci isSafe napsat také takto.

const isSafe = (password) => {
  if (password.length >= 12) {
    return true;
  }
  return false;
};

Proč není else potřeba? Zde je nuté oprášit logické uvažování. Pokud byla délka hesla dotatečná, funkce skončila u prvního return a k druhému se vůbec nedostala. Pokud se tedy vykonávání funkce dostalo až k druhému return, znamená to, heslo kontrolou neprošlo. Jinak by totiž funkce skončila mnohem dřív a sem bychom se vůbec nedostali. Nemusíme už tedy říkat žádné else a prostě vrátíme false.

Této strategii se říká časný návrat early return a zkušení programátoři jej používají velmi často. Je proto dobré si na tento způsob zápistu zvyknout už od samého začátku.

Cvičení: Vlastní funkce

3

Obsah elipsy

pohodička

Zlovolní zahrádkáři nám chtějí stížit výměru pozemků a proto si pořídíli pozemek ve tvru elipsy.

Elipsa

Z matematiky víme, že známe-li šířku a výšku elipsy, její obsah je polovina šířky krát polovina výšky krát číslo π.

Založte si prázdnou stránku s JavaScriptovým souborem a napište funkci ellipseArea, která spočítá plochu pozemku dle zadané šířky a výšky. Číslo π najdete v JavaScriptu v proměnné Math.PI.

4

Maximum ze dvou čísel

to dáš

Napište funkci max2, která vrátí větší ze dvou zadaných čísel. V JavaScriptu už na toto funkce existuje, jmenuje se Math.max. Pro účely tohoto příkladu se budeme tvářit, že o ní nevíme.

5

Kontrola DIČ

zapni hlavu

Všimněte si, že knihovna validator.js v době vzniku tohoto zadání neumí ověřit platnost českého DIČ (daňové identifikační číslo). Zkusme tedy takovou funkci napsat.

Formát DIČ sestává z předpony CZ a poté následuje devět nebo deset číslic. Tedy například

  • CZ123456789
  • CZ1234567890

Postupujte dle následujících kroků.

  1. Vytvořte prázdnou stránku s JavaScriptem a knihovnou validator.js.
  2. Vytvořte funkci isDIC s jedním parametrem inputStr, což bude řetězec, který chceme zkontrolovat.
  3. Jako první ve funkci zkontrolujte, jestli je vstupní řetězce kratší než 11 znaků. V takovém případě namá smysl dál nic dělat, protože vstup evidentně není DIČ. Vraťte tady z funkce false. Tím naše funkce končí. Všimněte si, že takto používáme vzor “časný návrat”.
  4. Dále ve funkci zkontrolujte, jestli je vstupní řetězce delší než 12 znaků. V takovém případě opět vraťte false.
  5. Dále ve funkce si do proměnné prefix uložte první dva znaky vstupního řetězce.
  6. Pomocí podmínky zkontrolujte, že proměnná prefix obsahuje přesně znaky CZ. Pokud ne, ihned vraťte false.
  7. Do promměné digits si uložte část vstupního řetězce od třetího znaku dále.
  8. Použijte metodu validator.isInt, která umí zkontrolovat, zda řetězec obsahuje pouze číslice. Pokud metoda vrátí false, ihned také vraťte false.
  9. Pokud funkce dospěla až do tohoto bodu, vstup prošel všemi testy. Můžeme vrátit true.
  10. Vyzoušejte svoji funkci v konzoli na různých vstupech a ověřte, že funguje.

Dobrovolné čtení na doma - alternativní zápis funkcí

V různých výukových materiálech se můžete setkat s alternativním zápisem funkce. Ten by pro naši obarvovací funkci vypadal takto.

function colorHeading(colorName) {
  const headingElm = document.querySelector('h1');
  headingElm.style.color = colorName;
}

Mezi těmito dvěma zápisy jsou co do významu drobné rozdíly. V tuto chvíli však ještě nemáme dostatečný aparát k tomu, abychom dobře vysvětlili, v čem přesně rozdíly mezi takto zapsanými funkcemi spočívají. Navíc v žádném tématu probíraném v rámci celé akademie se rozdíly mezi těmito zápisy neprojeví. Pro účely našeho kurzu tedy stačí si vybrat jeden zápis a toho se držet. My si vybereme ten první, kterému se odborně říká arrow funkce. Výhody tohoto zápisu spočívají v tom, že

  1. názorně ukazuje, že funkce se ukládá do proměnné, a je to tedy hodnota jako každá jiná,
  2. arrow funkce fungují uvnitř jednodušeji než funkce zapsané pomocí function,
  3. zápis arrow funkcí je většinou kratší a méně ukecaný.

Doporučené úložky na doma

6

Parsování data

to dáš

Bez použití knihovny dayjs napište funkci parseDate, která na vstupu obdrží řetězec obsahující datum ve formátu DD.MM.YYYY a vrátí objekt s jednotlivýnu částmi zadaného data. Příklad použití:

> parseDate('12.03.2015')
{ day: 12, month: 3, year: 2015 }
> parseDate('06.04.2021')
{ day: 6, month: 4, year: 2021 }
7

Formátování data

zapni hlavu

Bez použití knihovny dayjs napište funkci formatDate, která na vstupu obdrží objekt představující datum v následujícím formátu.

{ day: 12, month: 3, year: 2015 }

Funkce vrátí řetězec představující datum ve formátu DD.MM.YYYY. Příklad použití.

> formatDate({ day: 6, month: 4, year: 2021 })
"06.04.2021"

V tomto cvičení se vám jistě bude hodit metoda padStart. Zkuste také uvnitř těla funkce použít destrukturování.

8

Python zaokrouhlování

zapni hlavu

Jak jistě znalci jazyka Python dobře vědí, funkce round v tomto jazyce zaokrouhluje malinko jinak, než jsme zvyklí. Pokud je desetinná část čísla přesně 0.5, Python zaokrouhluje k nejbližšímu sudému číslu. JavaScriptová funkce Math.round naopak provádí zaokrouhlování způsobem, na který jste zvyklí, tedy pro 0.5 vždy nahoru. Někomu by se po po Pythonovském zaokrouhlování mohlo stýskat. Napište proto funkci jménem round, která bude zaokrouhlovat čísla na celé jednotky podle následujících pravidel.

  1. Pokud je desetinná část menší než 0.5, zaokrouhlujeme dolů.
  2. Pokud je desetinná část větší než 0.5, zaokrouhlujeme nahoru.
  3. Pokud je desetinná část přesně rovna 0.5, zaokrouhlujeme k sudému číslu. Tedy například 3.5 se zaokrouhlí na 4, naopak 2.5 se zaokrouhlí na 2.

V tomto cvičení se vám může hodit funkce Math.trunc, která umí odříznout desetinnou část čísla.

Dobrovolné úložky na doma

9

Maximum ze tří čísel

zapni hlavu

Napište funkci max3, která vrátí největší ze tří zadaných čísel. Opět se vyhněte použití funkce Math.max.