Kdy v JavaScriptu nepoužít operátor typeof

Školení, která pořádám

Operátor typeof se v JavaScriptu nejčastěji používá pro zjištění, zda je proměnná definovaná. Jeho výsledek se tedy obvykle porovnává s hodnotou 'undefined':

<script type="text/javascript">
if (typeof x == 'undefined') {
	alert('Proměnná x není definovaná.');
}
</script>

Pokud proměnná definovaná není a pokusíme se ji použít mimo tento operátor, tak dojde k chybě ReferenceError.

V naprosté většině případů ale nechceme zjistit existenci proměnné (protože ty si vytváříme sami), ale zajímá nás přítomnost nějaké vlastnosti v objektu. Přístup k neexistující vlastnosti objektu ale žádnou chybu nevyvolá a jednoduše vrátí hodnotu undefined – stačí tedy porovnání s touto hodnotou (včetně kontroly typu). Ještě elegantnější (a přesnější) je ale použít operátor in, který je přesně k tomu navržen:

<script type="text/javascript">
if ('webkitHidden' in document) {
	alert('Vlastnost webkitHidden existuje.');
	if (document.webkitHidden !== undefined) {
		alert('Zároveň nemá hodnotu undefined.');
	}
}
</script>

Rozdíl mezi operátorem in a porovnáním s hodnotou undefined se projeví v okamžiku, kdy v objektu existuje vlastnost obsahující tuto hodnotu: { x: undefined }.

Pokud nám stačí zjistit, jestli se vlastnost vyhodnotí jako true, tak žádnou samostatnou kontrolu existence vlastnosti dokonce ani nepotřebujeme, protože undefined se vyhodnotí jako false. Zbytečné používání operátoru typeof (pro jistotu, kdyby náhodou) kód znepřehledňuje a nejspíš i nepatrně zpomaluje.

Poznámka: Nedávno jsem psal také o nevhodném používání konstrukce isset v PHP.

Přijďte si o tomto tématu popovídat na školení JavaScript a AJAX.

Jakub Vrána, Seznámení s oblastí, 12.8.2011, diskuse: 16 (nové: 0)

Diskuse

ikona David Grudl OpenID:

Má to dvě úskalí. Jednak kvůli extrémní dynamičnosti JavaScriptu lze (ve většině browserů) undefined přepsat, což by se sice stávat nemělo, ale při tvorbě univerzálních skriptů je dobré i na tohle pamatovat. Dá se to řešit různě, docela zajímavý trik je místo undefined psát void 0.

A pak jsou situace, kdy bohužel přístup k neexistující vlastnosti objektu chybu vyvolá, kvůli chybě prohlížeče. Například http://bugzil.la/599479.

ikona David Grudl OpenID:

Napsal jsem to špatně, bez toho *neexistující*. Někdy pak lze použít "in" jako workaround.

ikona Jakub Vrána OpenID:

S undefined to je dobrá poznámka. Ve funkcích se to obvykle řeší pomocí (function (undefined) {})(). Případně jen prostě var undefined (uvnitř funkce).

U odkázaného bugu jde o chybu s přístupovými právy a dojde k ní i při použití typeof na tuto vlastnost. Takže tam nepomůže ani jeden zde uvedený postup a je potřeba chybu odchytit pomocí try/catch.

Karel:

Vlastnosti jsem vždy testoval pomocí prostého if:

<?php
if(document.getElementById) {
  document.getElementById("x")
}
?>

A in jsem používal jen v for smyčkách. Ale to byl úplně jiný in :-) . Díky za rozšíření obzorů.

ikona Jakub Vrána OpenID:

Dělám to stejně. Na tomhle místě by bylo přesnější použít typeof document.getElementById == 'function', ale považuji to za pedantství.

ikona v6ak:

To je otázka přístupu. Tady bych to nepovažoval za velký problém a možná bych to taky tak použil, ale mlže to být trochu matoucí. Na první pohled to může působit dojmem, že do else větve to jde jen při skrytí dokumentu, ale ono to tam může jít i při nepodpoře. Což není na první pohled patrné.

Občas si ale říkám, že by ses hodil spíše na nějaké překladače, JITky a další věci, kde je potřeba přemýšlet spíše o šetření. Neuvažoval jsi už o tom? Ve Facebooku se vyvíjí HiPHoP (nebo jak se to píše), nebudeš pracovat zrovna na něm?

ikona Jakub Vrána OpenID:

O šetření tady nejde. Zápis 'webkitHidden' in document mi přijde lepší než document.webkitHidden !== undefined a to zase lepší než typeof document.webkitHidden != 'undefined'. Lepší mi to přijde proto, že to lépe vystihuje význam toho, co chci udělat. Že to je trochu kratší a nejspíš i nepatrně rychlejší, je druhotné (i když příjemné).

Na HipHopu se pracovat nechystám, na Céčko se necítím – nějakou dobu jsem v něm dělal a zdálo se mi na mě moc složité (stejně jako třeba Perl, ostatně i některé obraty Pythonu nedokážu ocenit).

starenka:

Když si to nakousnul, dovolil bych si OT dotaz. Jaký obraty v Pythonu nedokážeš ocenit?

ikona Jakub Vrána OpenID:

Kontejnery, deskriptory, metaclassy. http://www.stdout.cz/clanky/vyvoj-aplikaci/…-programovaciho-jazyka/

ikona Aichi:

Testovani typu objektu ma i jina uskali, napr. predavany objekt mezi okny nelze jednoduse testovat pomoci instanceof, viz muj odkaz.

gondo:

a aka je teda odpoved na tu otazku v nadpise "Kdy v JavaScriptu nepoužít operátor typeof" ?
pretoze v texte riesis uplne odlisnu vec a to "přítomnost nějaké vlastnosti v objektu" ktora nema s typof nic spolocne, kedze na to nieje urcena a ako aj sam pises, vracia undefined

pride mi to ako zvolit nadpis "kdy v php nepoužít die()" a v clanku rozoberat ako pouzit echo() kedze die() nam predcasne ukonci spracovanie skriptu

ikona Jakub Vrána OpenID:

Operátor typeof by se podle mě neměl používat pro zjišťování existence vlastnosti v objektu. Mrzí mě, že to z článku není jasně zřejmé. Společného to má to, že se k tomu tento operátor velmi často používá. To je v článku také poměrně jasně uvedené.

Ondřej Štoček:

Výraz 'prop' in obj nerad používám, protože jméno property je zapsané jako string v uvozovkách. S tím nastávají problémy, pokud chcete skript minifikovat. Kvalitní minifikátor (čti google closure compiler se zapnutou volbou ADVANCED_OPTIMIZATIONS) nahradí všechny výskyty obj.prop zkratkou a.b, ale string 'prop' nenenahradí, což vyvolává nepředpokládané a špatně odhalitelné chyby.

ikona Jakub Vrána OpenID:

Díky za postřeh, to jsem nevěděl. Technicky vzato by se ale Closure Compiler dal vylepšit tak, aby počítal i s touto konstrukcí, ne?

Ondřej Štoček:

To je jen velmi těžko implementovatelné, protože ten string nemusí být konstantní. Je možné ho před použitím uložit do proměnné, provádět řetězící operace apod. Stejný případ je i míchání zápisu obj.prop vs obj['prop']. Google na svých stránkách doporučuje striktní konzistenci zápisu jmen atributů. Buď pouze tečkovou notaci, nebo zápis s uvozovkami. http://code.google.com/closure/compiler/docs/limitations.html

Ondra:

Jinými slovy "záměrně si oříznu potenciálně použitelný a zcela legitimní feature set, abych mohl používat SW třetí strany, který na to není nachystán". To se mi rozhodně nezamlouvá.

Navíc tu jasně vidím třeba use-case, kdy mi AJAXem ze serveru přijde nějaký datový objekt a já se zajímám o to, co všechno v něm je. I tady chci, aby mi Closure Compiler nahradil obj.prop za obj.a? :-)

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.