Jos tekee monikäyttöisiä JavaScript-järjestelmiä, jotka vaativat alustustoimenpiteitä sivun latauduttua, täytyy tietenkin kirjoittaa käsittelijä window.onload
-tapahtumalle. Joskus kuitenkin sattuu niin, että näitä järjestelmiä osuu samalle sivulle useampi, ja jokainen niistä tarvitsisi oman onload-koodinsa. Yksi vaihtoehto on tietenkin kirjoittaa aina uusi funktio, joka kutsuu erikseen jokaisen luokan onload-käsittelijää. On kuitenkin ikävä kirjoitella sellaisia joka sivulle, ja silloin voikin käyttää tässä koodivinkissä esitettävää jippoa.
Jos jotakin muuttujaa ei määritellä funktion sisällä mutta se on kuitenkin määritelty funktion ulkopuolella, viittaus tähän nimenomaiseen muuttujaan jää elämään funktiossa. Voidaan siis määritellä ensin listaobjekti ja sitten funktio, joka sitä käyttää, ja vasta lopuksi lisäillä tähän listaan sisältöä — joka siis päätyy funktion käyttöön.
Tässä koodivinkissä tehdään selkeyden (?) vuoksi ensin tavallinen olio, joka sisältää taulukon oikeasti kutsuttavista funktioista ja funktiot näiden lisäämiseen ja kutsumiseen. Sitten tehdään funktio, joka sisältää viittauksen tähän olioon ja kutsuu tästä funktiota, joka kutsuu edelleen näitä taulukon funktioita. JavaScriptissa funktiokin on sattumalta olio, joten lopuksi vielä lisätään sille oma jäsenfunktio, joka kutsuu edelleen sisäisen, "tavallisen" olion vastaavaa jäsenfunktiota. Näin saadaan aikaan funktio, jonka jäsenfunktiolla voidaan lisätä taulukkoon funktioita ja jota kutsumalla kutsutaankin kerralla kaikkia näitä lisättyjä funktioita.
Ensimmäinen listaus sisältää itse koodin, toisessa on esimerkki sen käytöstä.
// tapahtuma.js // Luokan "tapahtuma" muodostin function tapahtuma() { // Jäsenenä on lista funktioista this.lista = []; // Funktiota varten tarvitaan viittaus tähän olioon var _this = this; // Funktio kutsuu tämän olion funktiota "kutsu" this.funktio = function (parametri) { _this.kutsu(this, parametri); } // Lisätään vielä funktiolle jäsen, jolla kutsuttavia voi lisätä this.funktio.lisaa = function (f) { _this.lisaa(f); } } // Tässä on itse luokan funktio "lisaa" tapahtuma.prototype.lisaa = function (f) { this.lista.push(f); } // Lopuksi tarvitaan luokan funktio "kutsu", joka kutsuu listan funktioita tapahtuma.prototype.kutsu = function (_this, parametri) { for (var i in this.lista) { this.lista[i].call(_this, parametri); } } // Lisätään luokan muodostinfunktiolle vielä jäsenfunktio "uusi", // jolla saadaan näppärästi olion sijaan suoraan funktio tapahtuma.uusi = function() { var t = new tapahtuma(); return t.funktio; } // Lisätään valmiiksi window.onload-tapahtumalle tällainen window.onload = tapahtuma.uusi();
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xml:lang="fi" lang="fi" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Monta onload-tapahtumaa?</title> <script type="text/javascript" src="tapahtuma.js"></script> <script type="text/javascript"> /* <![CDATA[ */ // Lisätään nimetön funktio: window.onload.lisaa(function() { alert("Ensimmäinen onload-funktio!"); }); // Lisätään nimellinen funktio: function window_onload_2() { alert("Toinen onload-funktio!"); } window.onload.lisaa(window_onload_2); // Molempia lisättyjä kutsutaan sitten, kun sivu on ladattu. /* ]]> */ </script> </head> <body> </body> </html>
Toinen tapa:
// tapahtuma.js window.onload = function () { var lista = []; function kutsu() { for (var i in lista) lista[i](); } kutsu.lisaa = function (f) { lista.push(f); } return kutsu; }();
Suositeltavaa lukemista: http://en.wikipedia.org/wiki/Closure_
Kopeekka kirjoitti:
Suositeltavaa lukemista: http://en.wikipedia.org/wiki/Closure_
(computer_science)
Taisi jäädä viimmeinen sulje ulos linkistä. ;)
Pekka Karjalainen kirjoitti:
Toinen tapa:
// tapahtuma.js window.onload = function () { var lista = []; function kutsu() { for (var i in lista) lista[i](); } kutsu.lisaa = function (f) { lista.push(f); } return kutsu; }();
Tämä käy läpi myös arrayn prototyypin ja kutsuu kaikkia siellä olevia propertyjä/metodeja funktiona...
Array.prototype.$ = function(){ this[0] = 3; }; var a = [ function(){alert("moi"); } ]; alert(a[0]) // function(){ alert("moi"); } for (var i in a ) { a[i](); } alert(a[0]) // 3 (prototyyppimetodia kutsuttiin loopissa joka muutti funktiomuuttujan numeromuuttujaks)
Eli järjestykestä riippuen saatetana kutsua numeroa 3 funktiona. Eli for looppi pitäs olla, ei for in.
Aihe on jo aika vanha, joten et voi enää vastata siihen.