In precedenza abbiamo visto come realizzare uno slideshow object-oriented utilizzando un oggetto JavaScript di tipo singleton. In realtà esiste un altro modo per ottenere lo stesso tipo di oggetto: usare gli oggetti letterali. Anche se gli oggetti letterali sono assai diffusi e praticamente ogni framework JavaScript li utilizza, tuttavia risultano alquanto ostici da usare per chi è abituato ad usare un pattern basato sui costruttori (function
). Infatti gli oggetti letterali hanno delle caratteristiche peculiari che li rendono unici nel loro genere. Vedremo queste caratteristiche implementando uno slideshow che utilizza un oggetto letterale.
this
this
(eccellentemente illustrato in questo articolo) si riferisce all'oggetto corrente. In un oggetto letterale, l'accesso a tale riferimento dipende dallo scope corrente. Per esempio, il seguente caso funzionerà come ci si attende:
var Literal = {
test: 'Test',
method: function() {
alert(this.test);
}
};
Il metodo visualizzerà la stringa Test
. Nel caso di jQuery, invece, accade una cosa interessante: i metodi di questa libreria creano un nuovo scope al cui interno il riferimento a this
passa dall'oggetto letterale (come nel caso precedente) all'oggetto jQuery. Nel caso del nostro slideshow, possiamo avere una situazione simile alla seguente:
var Slideshow = {
wrapper: $('#slideshow-wrapper', '#slideshow'),
slides: $('img', '#slideshow-wrapper'),
previous: $('#prev', '#slideshow-controls'),
next: $('#next', '#slideshow-controls'),
index: 0,
getSlidePositions: function() {
var positions = [];
this.slides.each(function(i) {
var left = $(this).position().left;
positions[i] = left;
});
return positions;
},
// continua
};
Osserviamo le prime due proprietà:
wrapper: $('#slideshow-wrapper', '#slideshow'),
slides: $('img', '#slideshow-wrapper')
Ad uno sguardo superficiale si sarebbe tentati di riscrivere la proprietà slides
come:
slides: $('img', this.wrapper)
o come:
slides: $('img', Slideshow.wrapper)
che però restituiscono undefined
. Il motivo è semplice: essendo all'interno del wrapper $()
, this
fa riferimento a jQuery e quindi l'interprete JavaScript cerca la proprietà wrapper
come se fosse jQuery.wrapper
(che ovviamente non esiste) o come jQuery.Slideshow.wrapper
.
Invece nel caso del metodo getSlidePositions()
, this
non è più nel wrapper di jQuery, quindi punta a Slideshow
.
Closures
Il caso particolare della parola chiave this
si applica anche al caso delle closures create da molti metodi jQuery, come nel caso del gestore di eventi click()
:
slide: function() {
var offsets = this.getSlidePositions();
this.previous.click(function(event) {
Slideshow.index--;
if(Slideshow.index == -1) {
Slideshow.index = 0;
}
Slideshow.wrapper.animate({
left: - offsets[Slideshow.index]
}, 'slow');
event.preventDefault();
});
this.next.click(function(event) {
Slideshow.index++;
if(Slideshow.index == Slideshow.slides.length) {
Slideshow.index = 0;
}
Slideshow.wrapper.animate({
left: - offsets[Slideshow.index]
}, 'slow');
event.preventDefault();
});
}
All'interno del metodo click()
abbiamo usato la sintassi Slideshow.proprietà
perchè ora this
punta all'oggetto jQuery a cui è legato l'evento e non all'oggetto letterale Slideshow
. Invece all'esterno di tale metodo this
punta all'oggetto letterale, come di consueto.
Potete visionare l'esempio finale in questa pagina.