JavaScript/Addam
Cílem této učebnice základů programování v Javascriptu je naučit se dovednost pragmatického programování čili kodérství. Není přitom ani trochu záměr se učit programovat pěkně nebo efektivně, to si nechme na pozdější studium.
Projekt je čerstvě rozpracovaný od února 2021. Do května 2021 se jeho podoba trochu ustálí.
Cvičné úlohy
editovatSada třiceti cvičných úloh je dostupná na septima.dominec.eu. Úlohy jsou dělené do tří sad se vzrůstající náročností:
- úlohy 01-09 jsou vhodné pro osvojení úplných základů programování a pro pochopení, jak odevzdávat řešení,
- úlohy 10-19 vyžadují přemýšlení, ale zadání a případné rady vedou přímo ke správnému řešení,
- úlohy 20-30 jsou čistý freestyle, nicméně snad stále v mezích základní učebnice programování.
Samotný cvičný sandbox je psaný samozřejmě také v Javascriptu a je úplně v pořádku, pokud ho cokoliv z toho zdroje budete kopírovat, upravovat a používat pro jakékoliv účely.
Drobné rady
editovatVytvoření pole s předem určeným obsahem
editovatvar pole = [];
pole.push(1);
pole.push("b");
return pole;
...můžeme zapsat kratším způsobem:
return [1, "b"];
Cyklus for..of
editovatvar vysledek = [];
for (var i = 0; i < arg.length; i++) {
vysledek.push(2 * arg[i]);
}
Než abychom takhle procházeli čísla od 0 do arg.length - 1 a z nich pak vymýšleli arg[i], můžeme cyklem for...of projít přímo obsah pole:
var vysledek = [];
for (var x of arg) {
vysledek.push(2 * x);
}
Funkce Array.map
editovatPokračujeme v předchozím příkladu a ještě ho zjednodušíme:
var vysledek = arg.map(x => 2 * x)
Výraz x => 2 * x je ve skutečnosti sám o sobě funkce. Kdybychom nechtěli být až tak struční, můžeme si ho připravit předem, takže možná bude jasnější, co se vlastně děje:
function uprava(x) {
return 2 * x;
}
var vysledek = arg.map(uprava);
Podobný zápis jsme už používali dřív ve volání funkce Array.sort((a, b) => a - b)
Rozbalení pole do proměnných
editovatJe to vlastně opačný postup než prve zmíněné vytvoření pole s určeným obsahem. Obsah pole si můžeme rozbalit do několika proměnných a pracovat s nimi samostatně. Šetří to práci:
var arg = [10, 20, 30];
// místo obyčejného čtení položek:
var a = arg[0];
var b = arg[1];
var c = arg[2];
// ...můžeme napsat jeden příkaz:
var [a, b, c, ...zbytek] = arg;
Rozbalení pole do funkce
editovatChceme spustit nějakou funkci a parametry máme připravené v poli:
var parametry = [10, 20, 30];
function soucet(a, b, c) {
return a + b + c;
}
// obyčejný postup:
soucet(parametry[0], parametry[1], parametry[2]);
// s pomocí tří teček jde totéž udělat snáz:
soucet(...parametry);
Zvlášť mazané je to v kombinaci s funkcí, která bere libovolný počet parametrů – například jako Math.max. Jedním výrazem pak můžeme najít největší číslo v poli: Math.max(...arg); Z výukového hlediska by bylo užitečnější použít cyklus, ale co už.
Nedefinovaná hodnota proměnné
editovatHodnota undefined se dá použít v podmínkách, jenže při každém porovnání vrátí false. Dá se na to spolehnout:
var x;
x == 0; // false
x < 0; // false
x > 0; // false
(x < 0) || (x >= 0) // false
Math.abs(x) >= x // false
Hodnota undefined se objeví sama, když sáhneme, kam nemáme. Prohlížeč nehodí chybu a i na to se dá spolehnout:
var x = [10, 20];
x[2] // undefined
x[-1] // undefined
x.whatever // undefined
Když budeme používat podobné triky, bude asi těžší pak ten kód přečíst a pochopit. Dokud ale řešíme jednoduché školní příklady, nemusí to vadit. Tak například, když chci najít maximum v poli čísel:
var nejvetsi;
for (var i=0; i<arg.length; i++) {
if (arg[i] < nejvetsi) {
// nedělám nic
} else {
nejvetsi = arg[i];
}
}
Plytká řešení
editovatJedna hodně obecná rada: počítač má ohromný výkon, tak ho nešetřete. Psát programy tak, aby běžely rychle, chce dost zkušeností, a selský rozum většinou spíš uškodí – byť v něm bude upřímné snahy, kolik chce. Pokud není nutné řešit podrobnosti, je lepší se jim vyhnout. Čím kratší program napíšete, tím jednodušší je v něm pak opravovat chyby.
Výjimečnosti
editovatProgram jde zapsat na jeden řádek:
if (pocet == 0) {
return "";
} else {
return " ".repeat(pocet);
}
Řešení:
return " ".repeat(pocet);
Dva kroky
editovatProgram rozdělte na dva kroky, které se provedou postupně. Je to trochu delší, ale snad jednodušší na pochopení a později se podle toho dá vytvořit opravdu šikovné řešení.
var vysledek = [];
for (var cislo of pole) {
if (cislo > vysledek[0]) {
vysledek = [cislo];
} else if (cislo == vysledek[0]) {
vysledek.push(cislo); // řádky 7 a 8 jsou už jen } }
}
}
Řešení:
var maximum = 0;
for (var cislo of pole) {
if (cislo > maximum) {
maximum = cislo;
}
}
var vysledek = [];
for (var cislo of pole) {
if (cislo == maximum) {
vysledek.push(cislo);
}
}
Pak bychom mohli pokračovat tím, že první i druhý krok předchozího řešení naprogramujeme opravdu pěkně a efektivně:
var maximum = Math.max(...pole);
var vysledek = pole.filter(cislo => cislo == maximum);
Šikovné porovnávání
editovatZjednodušte program. Může být užitečné nastudovat, jak se chová hodnota undefined.
if (a < b) {
if (c < b) {
return true;
}
}
if (a < b) {
if (c == undefined) {
return true;
}
}
if (a == undefined) {
if (c < b) {
return true;
}
}
if (a == undefined) {
if (c == undefined) {
return true;
}
}
return false;
V prvním kroku řešení spojíme první dvě podmínky dohromady:
if (a < b) {
if (c < b) {
return true;
}
if (c == undefined) {
return true;
}
}
if (a == undefined) {
if (c < b) {
return true;
}
if (c == undefined) {
return true;
}
}
return false;
Dále obrátíme nerovnosti pomocí vykřičníku (negace). Využíváme toho, že (c < b) dává pro čísla stejné výsledky jako !(c >= b)
if (a < b) {
if (!(c >= b)) {
return true;
}
if (c == undefined) {
return true;
}
}
if (a == undefined) {
if (!(c >= b)) {
return true;
}
if (c == undefined) {
return true;
}
}
return false;
Teď nám dojde, že podmínka !(c >= b) platí i když (c == undefined). Tu druhou podmínku už není potřeba psát.
if (a < b) {
if (!(c >= b)) {
return true;
}
}
if (a == undefined) {
if (!(c >= b)) {
return true;
}
}
return false;
Teď si všimneme, že stejný trik jde udělat i s (a < b).
if (!(a >= b)) {
if (!(c >= b)) {
return true;
}
}
return false;
Pro řešení na jeden řádek se bude hodit spojka &&, čili „a zároveň“:
return (!(a >= b) && !(c >= b));
Takovéhle triky využívající undefined bývají riskantní, ale tentokrát se to vyplatilo.