Diskuze – Lekce 9 - OOP diář v JavaScriptu - Formátování a mazání záznamů
ZpětUpozorňujeme, že diskuze pod našimi online kurzy jsou nemoderované a primárně slouží k získávání zpětné vazby pro budoucí vylepšení kurzů. Pro studenty našich rekvalifikačních kurzů nabízíme možnost přímého kontaktu s lektory a studijním referentem pro osobní konzultace a podporu v rámci jejich studia. Toto je exkluzivní služba, která zajišťuje kvalitní a cílenou pomoc v případě jakýchkoli dotazů nebo projektů.


Chtělo by to v upoutávce na tuto lekci přepsat {PREVIOUS}
na
{NEXT}
. Takhle se u předchozí lekce zobrazuje v upoutávce odkaz
ještě na lekci předchozí.
V příští lekci, Formát JSON, do našeho objektového diáře v JavaScriptu přidáme několik dalších funkcí.
Václav Švarc:3.9.2021 17:39
Díky za tento postřeh, docela jsem se trápil jestli to není zase nějaká bezpečností kulišárna ze strany Chromu.
Vyřešil jsem nakonec právě použitím
element.insertAdjacentHTML("beforeend", text)
Stálo by za to upozornit na tuto okolnost i v článku.
Šimon Raichl:18.11.2021 0:01
Ahoj, neni to primo tak, ze pomoci innerHTML zrusis vsechny listenery ze vsech elementu, ve skutecnosti se prepisi vsechny puvodni elementy za nove, ktere uz nemaji zadne event listenery nastavene, ale z praktickeho hlediska je vysledek presne takovy, jaky jsi napsal.
Hodnocení:
- "...použijeme její metodu toLocaleDateString(),"
- Kód odstraňující položku: "bohužel" jen pro nematematiky - až na
drobnou odlišnost syntaxe používá metoda
filter
zápis množiny pomocí vlastnosti..je to docela sympatické 👍
Viz komentář (popis funkcí ok, ale obecně se zde porušuje zásadní pravidlo OOP a naučíte nováčky velmi hnusný návyk!)
Zdravíčko,
s touto lekcí začínám mít zásadní problém a měli byste se nad tím
velmi rychle zamyslet, než vychováte nevědomky programátory nemehla.
Bohužel se s tím setkávám i v praxi (v Javě), kdy se právě nováčci
učí na takových tutoriálech.
Nemám nic proti funkcím, které se tu probírají. Tento seriál je i v pořádku, co se týče přehlednosti a vysvětlování.
Problém ovšem je, že pokud je to seriál o OOP, tak by se zde měly i
základní myšlenky OOP dodržovat.
Nezlobte se na mě, ale OOP vychází především z faktu, že chce virtuální
svět a programování přiblížit co nejvíce reálnému světu.
No a teď si vezměte tu metodu vypisZaznamy()
V rámci čitelnosti kódu. Co byste asi tak čekali, když byste někde
viděli v seznamu možností .vypisiZaznamy()??
Pochybuji, že byste v takové metodě očekávali definici stylování datumu,
vytváření nějakého tlačítka, atd.
Ano, funguje to a přece by bylo hodně zbytečné v triviálním programu vytvářet metodu pro 2 řádky a pak ji volat.
Jenže v praxi se pak stane, že učíte nováčky neoddělovat správně
logiku programu.
Začíná to tím, že pak třeba vidím definici metody na 100 řádků. Metoda
se jmenuje loadData a já v ní najdu kromě SQL dotazu definici parsování,
formátu, mapování, if, který maže nějakou část databáze atd. atd.
atd.
No a končí to tím, že pak v business logice vidím entity, části JPA kódu atd.
Prostě toto se mi z hlediska OOP vážně nelíbí. To, že něco funguje, tak je sice hezké, ale metody jsou od toho (a proto se kódy snad člení na jednotlivé metody), aby každá metoda vykonávala takovou funkci, pro kterou je určená.
Také byste v reálném životě nečekali, že funkčnost nastavování
barvy ruky najdete v metodě ohniRuku(). Je to absurdita, ale toto se tady
takhle ty lidi učí.
Prostě ok, ať ta metoda vypisZaznamy() třeba ty ostatní metody volá, ale
ať v ní nejsou proboha ty definice!!!
Mimo jiné docílíte toho, že vám kód nebude odsunovat těla podmínek a
cyklů mimo obrazovku.
I to už jsem viděl, že vnitřní logika metody byla tak rozvětvená a
zanořená, že když jsem autoformátoval kód, tak mi skutečně kód odjel
mimo screen a já viděl cca 20 otevíracích závorek.
Prosím, přepracujte tuhle lekci a klidně kód rozšiřte, ale rozložte
definici logických částí do jednotlivých metod.
Je to triviální kód a lidi se to teprve učí, ano, ale právě je učíte
nechutný zlozvyk a myslím si, že i když každou tu logiku uvidí
samostatně, tak to budou i lépe chápat.
Jinak co se týče úkolu, funkcionalit a vysvětlování, tak za mě bezva práce.
Blanka Svobodová:3.8.2022 23:11
A ukázal bys prosím názorně, jak to elegantněji rozsekat? Já si to jako zelenáč neumím předělat zatím sama...respektive nefunguje mi to pak....díky předem.
Musela jsem si opravit dosavadní poktok kodu dle přiloženého souboru, v
nastavUdalosti nekam zmizel puvodne pridany radek
localStorage.setItem("zaznamy", JSON.stringify(this.zaznamy)); // přidaný
řádek.
Proč?
Lubor Pešek:4.8.2022 8:26
Věřím, že bys to zvládla i sama, ale nemám s tím problém.
Tak máš tu tuhle metodu:
vypisZaznamy() {
this.seradZaznamy();
this.vypisElement.innerHTML = "";
let posledniDatum = null;
for (const zaznam of this.zaznamy) {
if (zaznam.datum !== posledniDatum) {
const datum = new Date(zaznam.datum).toLocaleDateString(this.jazyk, {
weekday: "long",
day: "numeric",
month: "short",
year: "numeric"
});
this.vypisElement.insertAdjacentHTML("beforeend", `<h3>${datum}</h3>`);
}
posledniDatum = zaznam.datum;
this.vypisElement.insertAdjacentHTML("beforeend", `<strong>${zaznam.nazev}</strong>
<br>úkol ${!zaznam.splneno ? "ne" : ""}splněn`);
const smazatButton = document.createElement("button");
smazatButton.onclick = () => {
if (confirm("Opravdu si přejete odstranit úkol?")) {
this.zaznamy = this.zaznamy.filter(z => z !== zaznam); // Ponechá vše co není rovné proměnné zaznam
this.ulozZaznamy();
this.vypisZaznamy();
}
};
smazatButton.innerText = "Smazat záznam";
this.vypisElement.appendChild(smazatButton);
this.vypisElement.insertAdjacentHTML("beforeend", "<br>");
}
}
Základní myšlenka OOP je o tom, že by se měl virtuální svět co
nejvíce podobat tomu skutečnému a každý objekt takhle programovat.
Takovým typickým příkladem je programování židle a podlahy. Ty musíš
programovat židli tak, aby měla kromě svých atributů a funkcí i kontrolu
(validaci), že když ji na nějakou plochu položíš, že se nepropadne "pod
zem".
To samé i podlaha - ať na ní položíš cokoliv, ona to nesmí propustit.
V podstatě by stačilo takovou funkcionalitu naprogramovat jen jednomu
předmětu (třeba podlaze) a tím bys docílila kýženého výsledku. Jenže
ty se musíš na každou funkci dívat tak, aby byla v ideálním případě
použitelná i v jiném projektu.
A tak to máš i v praxi. Ty když bys třeba vytvářela papír, tak jej
nebudeš vytvářet pouze pro sešit (takže bys mu dala hned linky), ale
vytvoříš prázdný papír a ten, kdo bude vytvářet sešit, tak jej potom
následně a patřičně upraví podle toho, jak potřebuje.
No a teď si vem tuhle metodu - vypisZaznamy. Když ti řeknu, že existuje funkce vypsání záznamů, tak co bys od takové funkce očekávala? No nejspíš to, že odněkud vezme zdroj (ideálně z parametru, aby to bylo obecné) a někam to vypíše (ok, aby to bylo co nejvíc univerzálnější, tak bys mohla jako druhý parametr nastavit output, kam se to má vypisovat.
Rozhodně bys neočekávala, že tato metoda bude něco řadit, něco
stylovat či že bude vytvářet tlačítka.
Teď si vem, že bys tuhle metodu zavolala třeba v aplikaci, která bude
počítat goniometrické funkce.
No a najednou zjistíš, že budeš mít k dispozici posluchač pro
tlačítko...(respektive ty zavoláš metodu vypisZaznamy() a dostaneš
chybovou hlášku, že nemůže najít tlačítko smaž.. ) asi bys na to koukala jak půl
prdele z křoví.
To, o čem mluvím, tak sice na první pohled "zbytečně" navýší kód,
ale takhle by se mělo programovat (objektově).
Takže bych tuhle metodu osekal tak, aby skutečně POUZE vypisovala.
vypisZaznamy(output){
this.vypisElement.innerHTML = "";
this.vypisElement.insertAdjacentHTML("beforeend", output);
}
Samozřejmě tím najednou všechno chybí a je potřeba to postupně někde
dopsat a provolat
Takže je tu nějaký průchod tou aplikací. Schválně pojďme si vypsat, co
všechno ta metoda děá:
- promaže output
- v celém bloku bude třídit záznamy podle data
- vypíše unikátní datum
- vypíše názvy k příslušnému datu
- zjišťuje, zda-li byl úkol splněn nebo ne a následně jej vypíše
- vytváří nové tlačítko
- tlaítku nastavuje posluchače
- implementuje logiku tlačítka
- nastavuje tlačítko
- vypisuje tlačítko (ok, technicky to znamená, že přidá tlačítko do elementu)
trošku dost drsné a tohle bych určitě jen tak od takového názvu metody
nepředpokládal.
Určitě by nejideálnější řešením mohlo být, že by každý záznam byl
skutečně objekt, který bys vytvářela a nastavovala jeho atributy. Klidně
by ten objekt mohl obsahovat i to tlačítko (i když i to je věc
zobrazování, ale furt by to bylo lepší, než tohle).
Dejme tomu tedy, že bychom měli objekt, Zaznam, který obsahuje atributy:
datum, pole objektů úkol (úkol by měl dva atributy - název a jestli byl
nebo nebyl splněn).
V rámci tohoto úkolu to tu tuším tak i je (teď si to úplně nevybavím
dopodrobna, dělal jsem to před časem), ale o to víc je to smutné, že vše
je připraveno a následně se s těmi objekty nepracuje.
V hlavním běhu bys evidovala někde tyto objekty (třeba v nějakém poli).
Takže si můžeš vytvořit i funkci, která ti takové pole bude třídit
(podle data jednotlivých objektů).
U každého objektu bys řešila tedy evidenci jeho úkolů (vždy, když by se
přidával nový úkol, tak by se nejdřív prošlo pole objektů a zjistilo by
se, jestli takové datum už neexistuje a pokud ano, tak se jednoduše tento
úkol k takovému objektu přidá. Tohle je mimochodem práce s tzv. mapou,
která tady ještě zmíněna nebyla, ale přesně tohle by krásně řešila
mapa.
A nemusela bys pak v třízení řešit logiku, komu se co má přiřadit a už vůbec ne ve výpisu, kde bys takovou logiku neočekávala.
Takže když to všechno shrnu, tak bys prostě vyházela veškerou logiku z této funkce (vyházela, ne smazala) a použila ji před tím a trošku jinak a pro každou jednotlivou logiku vytvářela funkce, které bys potom postupně volala.
Výsledek se nesmí nijak změnit, kód ti sice naroste, ale důležitá
myšlenka hlavně tkví v tom, že když bys za čas chtěla kód upravit, tak
se budeš v něm lépe orientovat. Nehledě na to, že se lépe píšou unitové
testy.
ANO, může dojít k tomu, že pak budeš v uvozovkách kvůli blbému výpisu
vytvářet separátní metodu, takže místo 1 řádků napíšeš tři
řádky.
Teď ti prozradím něco z praxe. Je jedno, pokud má soubor třeba 10 000
řádků, pokud máš kód rozdělen do logických celků (metod, funkcí a
tříd). NIKDY si v praxi neprocházíš kód tak, že si otevřeš soubor a
čteš si ho od shora dolů. To je strukturované programování. V objektově
orientovaném programování si vždy čteš metodu, kterou chceš řešit. Pak
je už důležité, aby taková metoda byla co nejstručnější.
Věř, že lépe budeš upravovat metodu, která bude řešit třeba jen
formátování textu, než metoda, která bude mít v sobě formátování
textu, výpis, přidání tlačítka, parsování data, načítání JSONu atd.
atd. atd.
V praxi to doopravdy probíhá tak, že když debuguješ kód, tak jdeš po
jednotlivých metodách. Pokud metodu jednoznačně nepochopíš do 2 sekund (i
se čtením názvu), tak je špatně navržená.
To je i to, proč jsem ten komentář psal. Už je mi smutno, když třeba v práci otevřu metodu, která má ukládat data do databáze a první co v ní najdu, tak select, který mi nejdřív tahá data od jinud, abych část dat doplnil do textu, který chci uložit. Prostě když mám metodu ulož do databáze, tak ta metoda má skutečně jen použít již nastavenou sessionu a provolat metodu, která uloží text z parametru do databáze. Nic víc od toho nemůžu očekávat.
Po práci napíšu kód, jak bych si to konkrétně třeba já představoval. Není to úzus, určitě by se našlo i lepší řešení (vždycky existuje lepší řešení), ale bude to řešit problém, který já v tomhle vidím.
Zobrazeno 10 zpráv z 34.