# Č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 onload
Samozř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
.