JavaScript esetében is fontos szerepe van az időzítésnek, gyakran kell bizonyos időközönként elvégezni tevékenységeket, vagy bizonyos időkésleltetéssel dolgozni (tipikus eset animációk készítése). Ehhez két függvény áll rendelkezésre, a setTimeout és a setInterval, ezek azonban csak alapvető funkciót biztosítanak, ráadásul egyáltalán nem objektum-orientált megközelítésűek. Emiatt készítettem egy nagyon egyszerű Timer objektumot, amin keresztül ráadásul be tudok mutatni nektek néhány JavaScript best practice-t.
Legelső feladat a namespace létrehozása, hiszen nem szeretnénk fölöslegesen terhelni a globális névteret, ezt Javascript esetében a következőképp tehetjük meg:
var Webteam = Webteam || {};
Webteam.SimpleTimer = Webteam.SimpleTimer || {};
A névteret gyakran úgy képzik, hogy az első tag a cég neve, a második pedig a projekt neve. Mi közös megegyezésre általában a Webteam névteret használjuk a projektjeinkben.
Ezek után következik az objektum létrehozására, erre JavaScriptben számos lehetőség adott, most a példa kedvéért az egyik legkülönlegesebb módszert mutatom be:
A kód becsapós lehet, hiszen első ránézésre egy Timer függvény létrehozásának tűnhet, viszont ha jobban megnézitek, akkor ez egy névtelen függvény, amit a végén egyből meg is hívok, és a visszatérési értéke lesz maga a Timer objektum.
Ennek az az értelme, hogy privát tagváltozókat tudtam létrehozni. Ez annak köszönhető, hogy a JavaScriptben ha egy függvényen belül hozol létre egy belső függvényt, akkor a belső függvényben elérhetők a külső függvény lokális változói, még a függvény lefutása után is. A fenti példában például a start metódusban el tudom érni a külső függvény enabled lokális változóját is, még azután is, hogy a külső függvény régesrég lefutott. Ezáltal privát tagváltozókat hoztam létre.
A fent leírt mechanizmust hívják a JavaScriptben Closure-nek, sokan ezt tartják a nyelv legnagyobb erejének.
Tehát a recept a következő: a privát tagokat a külső függvény lokális változójaként hozom létre, amelyeket viszont publikussá szeretnék tenni, azokat a visszaadásra kerülő objektumba helyezem.
Ezek után viszont már világos az objektum működése, a start metódus időkésleltetéssel meghívja az update metódust, ami előbb meghívja az ontick metódust, majd saját magát időkésleltetéssel egészen addig, amíg le nem állítjuk a stop metódussal. Jól látható, hogy az időközönként lefuttatandó kódot az ontick metódusban kell implementálnia az objektum felhasználójának.
Az, hogy milyen időközönként járjon le az időzítő az interval private változó segítségével állíthatjuk. Kívülről ez a változó az Interval metóduson keresztül érhető el, ami egyben setter és getter is. Abban az esetben, ha paraméter nélkül hívjuk meg, visszaadja az interval aktuális értéket, ha paraméterrel, akkor egy ellenőrzés után kerül csak beállításra az érték. Ez szintén egy igen gyakran használt megoldás.
Ahogyan azt az objektum-orientált szemléletünkkel el is várjuk, a Timer objektum meg tudja magát védeni, hiszen az intervalnak nem lehet butaságot beállítani, valamint a kulcs működést biztosító update metódust sem lehet kívülről elérni, melynek közvetlen meghívása tönkretenné az egész Timer működését.
A fent bemutatott példának több haszna is volt reményeim szerint, egyrészt kaptatok egy nagyon egyszerű, mégis hatékony időzítő objektumot, másrészt megtanultátok a closure-ok jelentőségét és felhasználási módját a JavaScript nyelvben.