Objektové programování s knihovnou jQuery
od aichi
Už podruhé jsem řešil dotaz kamarádů jak docílit jednoduchého používání jQuery a objektového programování v Javascriptu. Problém to není neřešitelný, nicméně je to trochu drbání se levou rukou za pravým uchem, protože na to není jQuery stavěné.
...
Kamarád mi ukázal tento zdrojový kód, kde na řádku 19 musí uchovávat scope, aby ho mohl později v uzávěře na řádku 24 použít. Otázka, kterou položil byla, zda by se nešlo toho var nf = this; zbavit.
Pokud se na kód dobře podíváme, zjistíme, že je objektový a je zde definována "třída" NotificationFeed, na posledních řádcích se z této třídy vytvoří jedna instance a volá se metoda pro navěšení událostí. Události se navěšují pomocí jQuery, tedy metodou click a live (navěšení živých událostí). Tato metoda přebírá jako odkaz callback funkci, která bude při vyvolání události vykonána. Zde narážíme na první problém, protože my bychom potřebovali zavolat metodu konkrétní instance třídy NotificationFeed.
Můžeme volanou funkci zbindovat pomocí funkce bind, tedy natvrdo jí určit kontext ve kterém bude volána (z prototypové se stane neprototypová):
bind = function(obj,fnc){
return function() {
return fnc.apply(obj,arguments);
}
};
Pak bychom v konstruktoru NotificationFeed provedli zbindování standardně napsané prototypové metody:
//konstruktor
function NotificationFeed() {
this.target = $('#list');
this.clickFunction = bind(this, this.clickFunction);
}
//prototypova vlastnost
NotificationFeed.prototype.clickFunction = function(event) {
..
}
Pak bude metoda clickFunction vždy přiřazena své instanci, a budeme v ní moci využít klíčové slovo this, pro práci s daty této instance. Bohužel ouha, jQuery nám hází klacky pod nohy, všimněte si řádku 24 originálního zdrojáku:
nf.target.load(NotificationFeed.url($(this).attr('href')), {},
je zde použito klíčové slovo this! jQuery totiž callback metodu volá v kontextu jQuery objektu, který obaluje element, nad kterým byla událost (click) vyvolána. O toto this bychom nenávratně přišli a museli bychom ho nahradit získáním elementu přímo z objektu vzniklé události:
//FF & ostatni $(event.target) //IE $(event.srcElement)
Výsledná funkce by tedy vypadala nějak takto:
NotificationFeed.prototype.clickFunction = function(event) {
this.target.load(NotificationFeed.url($(event.target).attr('href')));
event.preventDefault();
}
}
Toto řešení samozřejmě není hezké, otázkou je, zda se s tím jde vypořádat jinak.
Vylepšené bindování
Bindovací metoda by mohla kromě uzávěry klíčového slova this uzavírat také jQuery objekt, v jehož kontextu je funkce volaná při vzniku události. Pak by vypadala takto:
bind = function(obj,fnc){
return function() {
var arg = [this];
for (var i = 0; i < arguments.length; i++){
arg.push(arguments[i]);
}
return fnc.apply(obj,arg);
}
};
Defakto zavádíme konvenci, že jako první parametr dostane volaná funkce vždy jQuery objekt, v jehož kontextu bude volaná, tudíž její deklarace může vypadat takto:
NotificationFeed.prototype.clickFunction = function(elem, event) {
this.target.load(NotificationFeed.url($(elem).attr('href')));
event.preventDefault();
}
}
Zdá se mi, že s tímto řešením a malou domluvou je jQuery použitelné s vlastními objekty. Nemusíme neustále uchovávat kontext do uzávěry ručně (var that = this), nemusíme stát před volbu jQuery a funkcionální programování versus objektové programování.
Jak tento problém řešíte vy? A řešíte ho vůbec?
Adresy zpětných odkazů pro tento příspěvek:
Trackback URL (right click and copy shortcut/link location)
3 komentářů
ad Aleš: díky za připomínku, pak by bylo řešení ještě složitější... Defakto to vede k řešení: pro každý element vytváříme jeden JS objekt, který se o handlování událostí na něm stará. Tuto filosofii vyznáváme při používání knihovny JAK.
23. 10. 09 18.20:01, 
