# Časté potíže
Odkazujte prosím na konkrétní kotvy (#), ne na čísla příspěvků.# Součet čísel versus součet řetězců
Vezmete-li např. hodnotu z textového
<input>u, skript s ní pracuje jako s řetězcem, i když je v ní vepsané číslo. Pokud k ní něco přičtete, výsledkem bude pořád řetězec, z
"1" + 5 vyjde
"15", nikoliv
6. Dosáhnout číselného součtu jde několika způsoby:
• Vynásobit řetězec jedničkou:
proměnná * 1 + 5.
• Místo přičtení odečíst zápornou hodnotu:
-(-proměnná) + 5.
• Přičíst kladnou hodnotu:
+proměnná + 5.
• Použít funkci
Number:
Number(proměnná) + 5.
• Použít funkci
parseFloat či
parseInt:
parseFloat(proměnná) + 5
# Detekce číselné soustavy v parseIntu
Funkce
parseInt umí být tak chytrá, až to někdy není hezké. Dokáže zpracovávat zápisy čísel v různých
číselných soustavách. Soustavu může programátor určit druhým argumentem,
parseInt("11111011010", 2) vrátí
2010,
parseInt("BADF00D", 16) vrátí 195948557 atd. — pokud ovšem není druhý argument uvedený, funkce se pokusí uhodnout soustavu podle konvencí zápisu čísel v JS. Což znamená, že:
•
parseInt("11") vrátí
11, jelikož předpokládá desítkovou soustavu,
•
parseInt("0x11") vrátí
17, jelikož předpokládá šestnáctkovou soustavu,
•
parseInt("011") vrátí v některých prohlížečích
9, jelikož předpokládá osmičkovou soustavu,
•
parseInt("08") vrátí v některých prohlížečích
0, jelikož předpokládá osmičkovou soustavu a v té číslice „8“ neexistuje —
na tohle pozor. V Opeře vám tato chyba projde.
Chcete-li se vyhnout autodetekci soustavy, vždy uvádějte druhý argument.
# Uchování hodnot proměnných v anonymních funkcích — lexikální uzávěry
Pokud vytváříte v cyklu timeouty nebo přiřazujete obsluhu události a potřebujete uvnitř vnitřní funkce pracovat s hodnotou proměnné cyklu, které nabývala v okamžiku vytvoření vnitřní funkce, musíte použít lexikální uzávěr. Názorněji:
•
Zbavení se kontextu (odkazu, provázání…) s proměnnou
•
Změna proměnné při načtení obrázku
•
Zajímavost — je to ekvivalentní kód?
•
Anonymní funkce a uzávěry
# Nepoužívejte eval, ani jeho obdoby
„
Používání eval, a jeho ekvivalentů, tedy new Function, setInterval(řetězec, číslo) a setTimeout(řetězec, číslo) je velké zlo (z anglického eval is evil
). Psát jakýkoliv kód jako řetězec a pak ho spouštět vyhodnocením je velmi nebezpečné. Můžou tím snadno vzniknout chyby, které se velmi těžko hledají. V 99 % případů* to ukazuje na špatný návrh aplikace a je to zbytečné.“ — Tak
pravil kolega
ah01 a měl svatou pravdu. JavaScript je stavěný tak, aby programátor při běžné práci
eval nepotřeboval. Lidé tu funkci používají z neznalosti rozumnějších postupů, vytvářejí tím nevýkonný a nebezpečný, ale hlavně méně přehledný a hůř udržovatelný kód. Obvykle narážejí na praktické problémy s (ne)escapováním uvozovek a s
předáváním argumentů, které nejsou vyjádřitelné řetězcem.
Funkcím
setInterval a
setTimeout dávejte jako první argument přímo funkci:
setTimeout(function() { alert("Baf!"); }, 5000);
setTimeout(bafnout, 5000); // máte-li nějakou funkci jménem „bafnout“Potřebujete-li změnit hodnotu vlastnosti objektu, jejíž jméno máte v proměnné, také
nepotřebujete eval.
*) Zbývá 1 % specifických případů, kdy se eval skutečně vyplatí používat, protože všechno zlé může být k něčemu dobré. Ale pokud vás někdo odkázal sem, ten váš případ to není.
# Rozdíl mezi voláním funkce a funkcí
JavaScript, na rozdiel od niektorých iných programovacích jazykov, môže pracovať s funkciou ako s dátovým typom. Výraz
f() znamená operátor volania funkcie aplikovaný na premennú
f. Jeho výsledkom je buď hodnota vrátená príkazom
return vo funkcii, alebo špeciálna hodnota
undefined. Výraz
f je tá funkcia samotná, ktorá môže byť uložená do inej premennej, predaná ako parameter pri volaní inej funkcie a podobne.
(Zformuloval _es.)
Názorně:
function kousnout()
{
if(confirm("Chceš kousnout?")) Zuby.kousnoutNávštěvníka();
}
dezert.onclick = kousnout(); // tím přiřadíte výsledek funkce kousnout (= undefined), která se v okamžiku přiřazení zavolá, většinou nežádoucí!
dezert.onclick = kousnout; // tím přiřadíte funkci kousnout, která se zavolá až při kliknutí na dezert
window.onload = alert("Ahoj."); // alert vyskočí hned při přiřazení, do onload se dá undefined
window.onload = function() { alert("Ahoj."); }; // alert vyskočí až při události onloadSamozřejmě, že i návratovou hodnotou funkce může být funkce, ale to není příliš obvyklý scénář.
# Dvojí přístup ke členu (vlastnosti/metodě) objektu
Zápisy
objekt.vlastnost a
objekt["vlastnost"] jsou ekvivalentní. Pokud se v názvu člena vyskytují znaky, které nejsou dovoleny v názvu identifikátoru (třeba „
-“ či „
[]“), je druhý zápis jedinou možností, jak se k dotyčnému členovi dostat. Mějme třeba tento kód:
<form name="vyber-cilu">
<input type="checkbox" name="planety[]" value="Dantooine"> Dantooine
<input type="checkbox" name="planety[]" value="Alderaan"> Alderaan
<input type="checkbox" name="planety[]" value="Yavin IV"> Yavin IV
</form>
Kdybychom chtěli zjistit, zda je zaškrtnutý Alderaan, použijeme
document["vyber-cilu"]["planety[]"][1].checked.
Zápis s řetězcem také umožňuje dostat se ke členovi, jehož název máte uložený v proměnné.
# Výsledkem výpočtu 1 - 0.9 není přesně 0.1
Na stejný problém narazíte prakticky ve všech programovacích jazycích — je zapříčiněn reprezentací reálných čísel v paměti (kdo by měl zájem,
zde je bližší vysvětlení).
•
javascript nevie pocitat
•
odchylka pri real (v kategorii PHP)
•
math.floor chybne vypočítava
# Používejte var
Příkaz
var deklaruje proměnnou v kontextu funkce, v níž je použit, nebo v globálním kontextu. Užívá se snadno:
var hrnecku = "kaši";
var počet = 5, nespočet = 6;
for(var i = 0; i < počet; i++) { … }Rozhodnete-li se navzdory doporučením vynechat
var, musíte počítat s několika úskalími:
• Všechny takto vytvořené proměnné jsou globální, a tudíž si mohou např. různé cykly v různých funkcích užívající tutéž iterační proměnnou jménem
i lézt do zelí.
• Nemůžete z nedeklarované proměnné číst dřív, než do ní zapíšete — vyskočila by na vás chyba, nikoliv roztomilé
undefined.
• Nedeklarovanou proměnnou je možné smazat operátorem
delete.
• Některé názvy proměnných
mohou kolidovat s nativními vlastnostmi globálního objektu (tj.
window).
• Přiřazení do nedeklarované proměnné
může vyvolat chybu v některých prohlížečích, pokud v dokumentu existuje element se shodným atributem
id či
name.