Objektum-orientált JavaScript
Nem, ez nem egy oximoron.
Egy régebbi melós projekt során merült fel a dolog, aztán azóta még nem volt nagyon időm írni róla, pedig akkor eléggé rákattantam a témára. Aztán most, hogy újraírtam a deadlime bejegyzés értékelő rendszerét valami korrektebb formába (azok a kis csillagok jobbra a bejegyzés után...), gondoltam ejtek néhány szót az objektum-orientált JavaScript szépségeiről.
A "JavaScriptben programozás szépségei", mint olyan, nem nagyon merült fel bennem soha, ha ezzel a nyelvvel kellett foglalkoznom (bár ebben biztos az is szerepet játszott, hogy még a különböző keretrendszerek elterjedése előtt az embernek if ágak egész erdejét kellett írnia, hogy a műve végül a főbb böngészőkben működjön). Szerencsére ezen sikerült változtatni.
A dolog alapjait egy, a weblaboron megjelent cikk elég jól leírja, én most inkább egy másik megközelítést szeretnék megemlíteni, amit ha a prototype.js-el együtt használunk, egy sokkal szebb szerkezetet kapunk.
Kezdetben ugye volt nekünk a függvény, mint olyan, amit egy alternatív módon is meg tudtunk adni:
var f = function(param)
{
alert('param: '+param);
};
f('valami');
Aztán van olyan dolog is a JavaScript-ben, hogy asszociatív tömb, amit valahogy így kell elképzelni:
var a = {
a : 'a értéke',
b : 'b értéke',
c : 'c értéke'
};
alert(a['a']);
A dolog ott kezd érdekessé válni, hogy ugye minden ilyen tömbelem elérésre létezik egy alternatív módszer is, ami már olyan "objektum-orientált" szerű:
var a = {
a : 'a értéke',
b : 'b értéke',
c : 'c értéke'
};
alert(a.a);
Itt jön a gondolat, hogy mi lenne, ha ezt a két módszert összekombinálnánk, és akkor legalább már ez az OOP dolog annyiban megvalósulna, hogy a függvényeket egy csokorba tudjuk gyűjteni:
var c = {
f : function(param)
{
alert('param: '+param);
}
};
c.f('valami');
Most már mondhatni alakul a dolog, de hát még a példányosítás hiányzik. Itt jönnek a képbe a függvények (tehát ezen a ponton már érdemes a weblabor cikk által nyújtott tudás birtokában lenni), amikkel lehet ilyen perverz dolgokat is művelni:
var f = function(param)
{
this.out = param;
this.alert_me = function()
{
alert('param: '+this.out);
};
};
var p = new f('valami');
p.alert_me();
Na kérem szépen, ez már egészen OOP, már csak helyre kell pofozni, mert ez így nem kicsit csúnya. Tehát, van a minden függvényenek alapból egy prototype
tulajdonsága (aminek tökéletesen semmi köze nincs a prototype.js keretrendszerhez), aminek ilyen asszociatív tömb formában szépen meg lehet adni a függvény további tulajdonságait is. Valahogy így:
var c = function(param) {
this.out = param;
};
c.prototype = {
alert_me : function()
{
alert('param: '+this.out);
}
};
b = new c('másvalami');
b.alert_me();
A dolog csúnyasága csak annyi, hogy a konstruktor és a többi függvény el van választva egymástól. Ezen segít a prototype.js, aminek van egy Class.create()
függvénye. Ennek segítségével az osztályunk initialize() függvénye automatikusan meghívódik új példány készítése esetén, és átadódnak neki a paraméterek:
var c = Class.create();
c.prototype = {
initialize : function(param)
{
this.out = param;
}
alert_me : function()
{
alert('param: '+this.out);
}
};
b = new c('másvalami');
b.alert_me();
Emiatt az egy dolog miatt mondjuk még nem lenne érdemes a prototype.js -t használni, mivel ez a része csak ennyiből áll:
var Class = {
create : function() {
return function() {
this.initialize.apply(this, arguments);
};
}
};
De mivel egyéb jó tulajdonságokkal is rendelkezik, ezért nézzünk is meg még egy kis példakódot, hogy jobban előjöjjenek a dolog szépségei:
var Gomb = Class.create();
Gomb.prototype = {
initialize : function(id)
{
this.object = $(id);
Event.observe(
this.object,
'mouseover',
this.evt_over.bindAsEventListener(this)
);
Event.observe(
this.object,
'mouseout',
this.evt_out.bindAsEventListener(this)
);
Event.observe(
this.object,
'click',
this.evt_click.bindAsEventListener(this)
);
},
evt_over : function(evt)
{
alert(this.object.id+' mondja: Hurrá, fölöttem van az egér!');
},
evt_out : function(evt)
{
alert(this.object.id+' mondja: Már nincs :\'(');
},
evt_click : function(evt)
{
alert(this.object.id+' mondja: Köszi, hogy megnyomtál!');
}
};
var my_button = new Gomb('id_button');
A használt prototype.js függvényekről további információ: Class.create(), Event.observe(), Function.bindAsEventListener(). Ennyit mára, JavaScriptekben gazdag további szép napot. :)