JavaScript je ZLO 2.0

nenávistné poznámky vzteklého kodéra

Argumenty funkcí - stálý zdroj zábavy

Co se týče funkcí v JavaScriptu, žádný argument není povinný. To je sice lepší než kdyby byly povinné všechny, nicméně zas až taková výhra to taky není.
Jestli o argumentech funkcí víte všechno tak už ani dál nečtěte protože tohle bude jen a jen o nich.

Nejdříve něco základních znalostí:

Vlastnosti length a arity: máme-li funkci definovanou předpisem var fn = function (a, b, c) { ... };, počet očekávaných argumentů můžeme kdykoli zjistit z atributu length ( fn.length == 3 ) nebo z atributu arity (fn.arity == 3).

Objekt arguments: zavoláme-li funkci, všechny předané argumenty se uloží do objektu arguments které je lokálně dostupné uvnitř této funkce. Zavoláme-li např. funkci f(10, 20), bude arguments[0] == 10 a arguments[1] == 20. Vlastnost arguments.length obsahuje skutečný počet předaných argumentů.

Jak správně podotkl Oswald, objekt arguments se sice tváří jako číslované pole ale není tak docela pole (tzn. arguments != instanceof Array).

Jestliže funkci f(a, b, c) { ... } zavoláme f(10, 20), bude f.arity == 3 a uvnitř prováděné funkce bude arguments.length == 2. Můžeme tak snadno zjistit zda byly zadány všechny předepsané argumenty. V tomto případě nebyly a proto typeof c == "undefined".

Jak vidno, žádný argument není tak docela povinný a naopak, funkci můžeme zavolat i s větším počtem argumentů než má předepsáno. “Nadbytečné” argumenty jsou dostupné pouze z objektu arguments.

Reference arguments.calee: toto je reference na funkci která právě probíhá, tedy na tu které patří pole arguments. Této reference lze využít k rozličným fintám, například pokud chceme aby funkce proběhla právě jednou, můžeme napsat

myNs.myFn = function () {
    if (arguments.calee.done) {
        return false; // function already run - exit
    } else {
        arguments.calee.done = true; // function runs first time - continue
    }
    …
};

Ošetření argumentů funkce

Argumenty které nejsou povinné by měly mít vhodné “default” hodnoty. Pro přehlednost by měly být uvedeny hned na začátku funkce:

myNs.myFn = function (myNum, myBool) {
    if (typeof myNum == "undefined") {
        myNum = null;
    }
    if (typeof myBool == "undefined") {
        myBool = true;
    }
    …
};

U argumentů, kde nemůže dojít k omylu způsobenému typovou konverzí, můžem použít zkrácenou formu

myNs.myFn = function (myObj) {
    myObj = myObj || null;
    …
};

která je ještě relativně dobře čitelná, ale raději ji používejte jen když opravdu dobře víte co děláte a jen v takto jednoduchých případech.

Argumenty které jsou povinné doporučuji ponechat neošetřené - jednak se tím šetří kód (přenos po síti bývá často stále ještě dost pomalý), je to kompatibilní se staršími Internet Explorery a pokud argument nepřijde, program obvykle rychle havaruje a tedy se chyba snadněji hledá.
Pokud budete chtít být opravdu poctiví, doporučuji vyhodit okamžitě výjimku, což však není kompatibilní se staršími MSIE.

myNs.myFn = function (myArg) {
    if (typeof myArg == "undefined") {
        throw "Crap! Exception in function myNs.myFn - argument myArg is missing";
    }
    …
};

Konvence pro řazení argumentů

Základní řazení argumentů při deklaraci funkce je určené omezeními JavaScriptu - nejdříve jsou vždy povinné argumenty a za nimi teprve nepovinné. U nepovinných argumentů je to složitější, nicméně je vždy dobré řídit se zdravým rozumem a dávat dopředu argumenty které budou uživatelé funkce častěji nastavovat.

KISS

Závěrem bych ještě dodal jednoduchou poučku která platí nejen pro funkce a jejich argumenty:
“Keep it simple stupid” neboli “udělej to jednoduše jako pro blbečky”. Prostě si představte toho nejhloupějšího programátora na světě jak luští vaši funkci a snaží se zjistit co vlastně dělá a pak to napište tak aby to pochopilo i malé dítě (a tedy i já).



5 Komentářů k článku “Argumenty funkcí - stálý zdroj zábavy”

  1. Oswald:

    Jenom drobné upřesnění: arguments není pole (teoreticky se jedná o instanci třídy Arguments). Sice např. Opera skutečně předává array, ale Firefox i IE vrací na test “arguments instanceof Array” false a minimálně ve Firefoxu nejsou u objektu arguments k dispozici metody jako push apod.


  2. richard:

    Je to tak, informaci jsem upravil. Abych řekl pravdu, “rádoby objektová” část JavaScriptu mě velice irituje. Kdyby autoři neblbli a ponechali ho jako “jazyk založený na seznamech” kterým původně byl, mohl být JavaScript mnohem přehlednější a nedocházelo by k takovým šílenostem co ukazuje Douglas Crockford.


  3. Hanz:

    V části “Ošetření argumentů funkce” se mají předávat argumenty myNum a myBool, ale ty tam posléze kontroluješ argument myInt a né myNum (i když bych řekl, žes chtěl raději napsat místo myNum myInt )


  4. richard:

    Máš recht, opraveno. Ale raději jsem napsal myNum, myslím že je to vhodnější.


  5. Jaroslav Procházka:

    no zadna slava mely by ste to zlepsit


Přidejte komentář

For spam detection purposes, please copy the number 2733 to the field below:




Weblog "JavaScript je ZLO 2.0" pohání všelijak překopaný WordPress,
XHTML je skoro validní, celkem respektuje Dogma W4 ale ne úplně