Conoscere javascript: this

Per utilizzare javascript al meglio occorre sapere che la keyword this è un false-friend, non ha lo stesso comportamento che ha all’interno di una classe di un linguaggio ad oggetti. Javascript è un linguaggio ad oggetti basato su prototipi, non ha il concetto di classe.

Al contrario di tutti i nomi this viene risolto utilizzando scoping dinamico, può quindi capitare che non denoti l’oggetto corrente!

La tecnica di scoping adottata da un linguaggio determina come avviene l’associazione tra un nome all’interno del programma e un valore precedentemente definito (variabile, funzione, etc. ) , questo processo viene comunemente chiamato risoluzione dei nomi.
In realtà non è propriamente vero, ma non è questo il luogo per un corso di teoria dei linguaggi di programmazione.

var x = 'global';
function(){
   var x = 'local';
   console.log(x); //E' la tecnica di scoping che decide con quale variabile x deve essere risolto questo riferimento
}


Scoping statico
Approccio usato dalla maggior parte dei linguaggi odierni, tra cui con l’eccezione di this c’è anche javascript.

La risoluzione di un nome avviene solamente in base alla struttura del codice, nella maniera che ci risulta più intuitiva; viene risolto con la dichiarazione più vicina.

Scoping dinamico
Approccio più raro in cui la risoluzione del nome dipende dall’esecuzione del programma, a parità di codice può cambiare di volta in volta!
Un nome viene risolto con la dichiarazione eseguita più di recente, indipendentemente da quanto questa sia distante nel codice, è quindi il flusso di esecuzione che determina la risoluzione dei nomi.

Nota che javascript ogni volta che si accede ad un oggetto fa puntare this a tale oggetto, il grosso dei problemi si hanno quando si passano funzioni con dentro riferimenti a this.

Esempi

//Il construttore di un semplice oggetto di test
var Obj = function(msg){
   this.msg = msg;
   this.callMe = function(){
      console.log(this.msg);
   }
}

//Creo un oggetto il cui ruolo è quello di salvarsi callback di altri oggetti per poi richiamarle
var ObjManager = new function(){
   this.msg = "Sono l'ObjManager";
   this.callback = undefined;
}

//Setto il metodo dell'oggetto di test come callback
ObjManager.callback = (new Obj("Sono l'oggetto")).callMe;

ObjManager.callback();

In console quello che troveremo eseguendo questo codice sarà “Sono l’ObjManager”, questo perché quando accediamo a ObjManager per accedere a callback javascript riassegna automaticamente a this  ObjManager, l’ultimo oggetto acceduto; mentre quando viene chiamata la callback non c’è alcun riassegnamento in quanto non è un oggetto.

Da notare che anche l’accesso ad un array causa il riassegnamento di this in quanto in realtà sia gli array sia gli oggetti sono dizionari, mappe chiave-valore.

Adesso come ne usciamo ? Sfruttando una bellissima cosa chiamata chiusura lessicale.

var Obj = function(msg){
   this.msg = msg;

   //THIS è un normalissimo nome di una variabile qualsiasi, ma permette di mantenere un puntatore all'oggetto
   var THIS = this;
   this.callMe = function(){
      console.log(THIS.msg);
   }
}

var ObjManager = new function(){
   this.msg = "Sono l'ObjManager";
   this.callback = undefined;
}

ObjManager.callback = (new Obj("Sono l'oggetto")).callMe;

ObjManager.callback();

Adesso in console ci troviamo “Sono l’oggetto”.

In breve: con la chiusura lessicale nell’entità che rappresenta la funzione, oltre al corpo della stessa, è salvato tutto il necessario per risolvere i nomi non locali alla funzione, come per l’appunto THIS.  Quindi possiamo passare la funzione come parametro quante volte vogliamo, ma il THIS all’interno del corpo riferisce sempre alla variabile che abbiamo dichiarato nel corpo del costruttore dell’oggetto originale e punta proprio a quest’ultimo.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *