Metodi di oggetti come callback
Un ambito nel quale possiamo utilizzare con successo le closure riguarda l'assegnazione di un metodo di un particolare oggetto come callback di un evento scatenato dal DOM. La soluzione proposta in precedenza utilizzava la funzione setScope per forzare lo scope di un particolare metodo nel momento in cui l'utente faceva scatenare l'evento.
In questo modo però non è più possibile risalire allo scope "originale" che rappresenta l'oggetto DOM sul quale l'evento è scattato. Questo può essere utile in caso di funzioni callback dinamiche che possono agire su diverse tipologie di elementi DOM. Una possibile soluzione per avere a disposizione sia l'oggetto DOM che l'oggetto JavaScript potrebbe essere questa:
<script type="text/javascript">
var listener = function() {
this.message = "Hai cliccato su di me";
this.onclick = function() {
var listener = this;
return function() {
alert("MESSAGGIO: " + listener.message + "nTAGNAME: " + this.tagName);
}
}
}
var clickListener = new listener();
window.onload = function() {
document.getElementsByTagName("button")[0].onclick = clickListener.onclick();
document.getElementsByTagName("a")[0].onclick = clickListener.onclick();
document.getElementsByTagName("img")[0].onclick = clickListener.onclick();
}
</script>
<button>Bottone 1</button>
<a href="#">Link 1</a>
<img src="http://html.it/common/img/logo2.gif"/>
In questo esempio abbiamo definito la classe listener
che presenta una proprietà contenente un semplice messaggio ed un metodo che crea una closure che verrà successivamente assegnata come callback. La parte più interessante dello script è la riga var listener = this;
. Questa riga, nonostante sembri di una banalità incredibile, rappresenta l'essenza di tutto il programma. In questo modo creiamo un alias per riferirsi all'oggetto listener
in modo da averlo a disposizione anche all'interno della closure; così facendo evitiamo che this
venga "sovrascritto" dallo scope più interno che in questo caso è rappresentato dall'oggetto DOM scatenante l'evento. All'interno della closure possiamo infatti riferirci al listener corrente tramite listener
e all'oggetto DOM tramite this
. Questo è un classico esempio di scope mixing, ovvero la possibilità di avere a disposizione nella stessa funzione diversi livelli della scope chain.