C'è chi dice non sia utile, c'è chi dice non sia argomento semplice tanto quanto java o C# ... di fatto sviluppare JS in questo modo ne comporta i soliti vantaggi della programmazione ad oggetti, soprattutto oggi che JS sta prendendo sempre più piede, attraverso una semplicità nota ed intrinseca, tipica del JavaScript stesso.
Questa pillola non è pensata per chi è a digiuno di JavaScript, bensì per chi ne conosce potenzialità e sintassi ma non l'ha ancora approfondito con gli oggetti.
Cosa si intende per classe
Una classe è una porzione di codice portabile e riutilizzabile in grado di effettuare una o più operazioni attraverso metodi (funzioni interne pubbliche o private) o di restituire informazioni attraverso i parametri (variabili interne pubbliche o private).
Una classe in JavaScript è una funzione ?
Si, è possibile affermarlo, ma non è altrettanto possibile farlo nei confronti dell'oggetto che ne istanzia una. Se una classe è di fatto un instanceof Function, un'istanza della classe non è un instanza di funzione ma esattamente un'istanza del nome di quella funzione, ovvero un'istanza di quella classe, o per comodità un oggetto "Classe".
Una funzione può quindi essere usata sia come classe che come funzione ?codice:function Test(){}; // funzione Test var test = new Test(); // oggetto Test // Test è istanziato come classe [grazie a new] alert(Test instanceof Function); // true alert(test instanceof Function); // false alert(test instanceof Test); // true
La differenza fondamentale tra l'utilizzo della funzione Test come tale o come classe, è che nel secondo caso possiamo sfruttare in un secondo momento il parametro interno.codice:// funzione Test function Test(){ // assegnazione di un parametro interno pubblico this.parametro = "Ciao Mondo"; // operazione di funzione alert(this.parametro); }; // chiamata a funzione Test Test(); // Ciao Mondo // istanza di un nuovo oggetto Test var test = new Test(); // Ciao Mondo
Questo accade perchè il riferimento all'interno della classe Test, ovvero il valore this, perde il referente di se stesso non appena la funzione cessa la sua esecuzione e nel caso di una chiamata diretta, Test.parametro, questo valore di fatto è come se non esistesse, visto che la funzione Test non è stata richiamata e visto che this.parametro è solo una parte di codice presente all'interno di questa funzione.codice:// richiamo il parametro della funzione alert(Test.parametro); // undefined // richiamo il parametro dell'oggetto di tipo Test alert(test.parametro); // Ciao Mondo
Per questo è necessario istanziare un oggetto attraverso l'uso di Test come classe e non come funzione (sempre grazie a new), per permettere al codice interno alla classe di risalire a se stesso in qualunque momento, perlomeno finchè l'oggetto istanziato ha una validità all'interno del proprio scope.codice:alert(new Test().parametro); // Ciao Mondo alert(Test().parametro); // Errore: Test has no properties
Scope ? ... e perchè non Rubamezzetto ?
Lo scope è lo spazio in cui una variabile, una funzione o in generale un oggetto, risulta essere raggiungibile o utilizzabile. Lo scope è indispensabile per capire gli oggetti JavaScript ed il JavaScript stesso. Una volta capito alla perfezione come procedere per avere o non avere un determinato scope per ogni metodo, funzione, variabile o oggetto che sia, la strada sarà tutta in discesa.
La variabile parametro all'interno di Test non cessa comunque di esistere dopo l'assegnazione ad oggetto, poichè il suo scope persiste all'interno di quella porzione di codice.codice:// funzione Test function Test(){ // parametro interno pubblico this.parametro = "Ciao Mondo"; // parametro interno privato var parametro = "Ciao Mondo Parallelo"; // operazione di funzione alert(parametro); }; // istanza di un nuovo oggetto Test var test = new Test(); // Ciao Mondo Parallelo alert(test.parametro); // Ciao Mondo
Ma la parola var prima del nome della variabile è indispensabile ?codice:// funzione Test function Test(){ // parametro privato var parametro = "Ciao Mondo Parallelo"; // parametro pubblico this.parametro = "Ciao Mondo"; // metodo pubblico this.leggiParametro = function() { alert(parametro); }; }; var test = new Test(); // ... non accade niente ... test.leggiParametro(); // Ciao Mondo Parallelo alert(test.parametro); // Ciao Mondo test.leggiParametro(); // Ciao Mondo Parallelo
La parola var è una delle migliore amiche di JavaScript ed è quella che definisce esattamente lo scope di una variabile.
Dichiarando invece la variabile di funzione con var non si rischia di sovrascrivere una globale ne di ritrovarsi sovrascritta la variabile di funzione.codice:var parametro = "Variabile Globale"; // una variabile globale non ha bisogno della parola var // ma non è nemmeno sbagliato usare la parola var per dichiarare una globale function Test(){ // parametro privato senza var parametro = "Ciao Mondo Parallelo"; this.leggiParametro = function() { alert(parametro); }; }; alert(parametro); // Variabile Globale var test = new Test(); test.leggiParametro(); // Ciao Mondo Parallelo alert(parametro); // Ciao Mondo Parallelo
Con var possiamo quindi stare sempre tranquillicodice:function Test(){ // parametro privato senza var parametro = "Ciao Mondo Parallelo"; this.leggiParametro = function() { alert(parametro); }; }; var test = new Test(); test.leggiParametro(); // Ciao Mondo Parallelo var parametro = "Variabile Globale"; test.leggiParametro(); // Variabile Globale
Ma se ho una variabile privata non posso risalire a quella globale ?codice:function Test(){ var parametro = "Ciao Mondo Parallelo"; this.leggiParametro = function() {alert(parametro);}; }; var parametro = "Variabile Globale"; var test = new Test(); test.leggiParametro(); // Ciao Mondo Parallelo alert(parametro); // Variabile Globale test.leggiParametro(); // Ciao Mondo Parallelo
Una variabile globale è come se fosse un parametro della super classe window, è quindi sempre possibile raggiungere il suo valore anche usando omonimi all'interno di una classe.
Perchè usare variabili private e non globali all'interno di una classe ?codice:function Test(){ var parametro = "Ciao Mondo Parallelo"; this.leggiParametro = function() {alert(parametro);}; this.leggiParametroGlobale = function() {alert(window.parametro);}; }; var parametro = "Variabile Globale"; var test = new Test(); test.leggiParametroGlobale(); // Variabile Globale test.leggiParametro(); // Ciao Mondo Parallelo
Non c'è un motivo assoluto per scegliere di usare una variabile privata piuttosto che una globale se non quello di essere certi che il valore della variabile o del valore resttuito dalla funzione privata sarà esattamente quello che ci aspettiamo all'interno dell'oggetto e che nessuno potrà quindi modificarlo. Uno dei limiti più consistenti della programmazione ad oggetti in JavaScript è infatti proprio quello di non poter garantire consistenza agli oggetti.
Per consistenza si intende la possibilità di impedire ad altri di modificare metodi o parametri pubblici dei nostri oggetti.
Qualora un metodo od una variabile dovessero essere utili solo per poter utilizzare altri metodi pubblici è consigliabile sfruttare funzioni o variabili interne, quindi private, al fine di limitare la possibilità ad altri di modificare porzioni indispensabili di codice.codice:function Test(){ this.metodoPubblico = function() { alert("Ciao Mondo"); }; }; var test = new Test(); test.metodoPubblico(); // Ciao Mondo // un altra porzione di codice fa, "per sbaglio", questa operazione test.metodoPubblico = "Ciao Mondo"; // operazione sempre lecita per un oggetto // il metodo pubblico dell'oggetto test è stato distruto test.metodoPubblico(); // Error: test.metodoPubblico is not a function
Ma perchè continui a dire "altri" ? Sono io che scrivo le classi ed il codice ... !!!
Le considerazioni da fare sono almeno un paio
- in applicativi dove il codice è veramente tanto e le classi create da centinaia di linee può capitare di "dimenticarsi" di un nome di metodo o parametro già usati per altri scopi, limitare l'utilizzo di nomi al fine di avere pubblici solo quelli fondamentali per l'oggetto può essere di aiuto
- JavaScript si include nelle pagine con una facilità impressionante, Google, come la super mega libreria "Cinema Effects with only 200Kb", potrebbero in qualche modo cambiare il vostro codice e viceversa, senza usare i giusti accorgimenti potreste voi stessi distruggere il codice di altre librerie presenti che avete incluso nella pagina
Ok per le variabili, qualcosa sulle funzioni / metodi privati ?
Assegnare un parametro o un metodo pubblico è molto semplice, basta usare this davanti al nome del metodo o parametro. Allo stesso tempo all'interno di un metodo pubblico il this sarà riferito all'oggetto stesso.
Questo permette al metodo pubblico di risalire ad altri metodi pubblici o variabili pubbliche attraverso l'uso del prefisso this, riferendosi sempre all'oggetto stesso.codice:function Test(){ this.confronta = function(variabile) { alert(this === variabile); }; }; var test = new Test(); test.confronta(test); // true test.confronta(Test); // false
Quanto detto serve per introdurre i metodi privati, o per meglio definirli, le funzioni a scope locale. Queste funzioni possono essere innestate nella classe come nel metodo pubblico e sebbene non abbiano la parola var davanti hanno le stesse identiche regole di scope delle variabili.codice:function Test(){ this.mostraPippo = function() { alert(this.pippo); } }; var test = new Test(); var oggetto = new Test(); oggetto.pippo = "Yuk!"; oggetto.mostraPippo(); // Yuk! test.mostraPippo(); // undefined
In questo "semplice" esempio c'è molto di quanto detto sullo scope, sulle funzioni innestate e sui metodi privati. E' importante notare che la funzione locale al metodo mostraAvviso nonsovrascrive quella privata definita nello scope della classe (la prima), come è importante notare che la funzione innestata al metodo mostraAvviso non ha in questo caso nemmeno bisogno di una variabile come argomento, poichè lo scope della variabile messaggio, inviata al metodo dell'oggetto, ha validità per tutto il metodo stesso ed ogni porzione di codice creata al suo interno potrà sfruttare questa variabile.codice:function Test(){ // "metodo" privato / funzione privata function avviso(){alert("Avviso Generico")}; this.avviso = function() { avviso(); }; this.mostraAvviso = function(messaggio) { // funzione locale function avviso(){alert(messaggio)}; avviso(); }; }; var test = new Test(); test.mostraAvviso("Ciao Mondo"); // Ciao Mondo test.avviso(); // Avviso Generico
Altra nota di rilievo è che in questo caso non è possibile, una volta oscurato lo scope della prima funzione "avviso()", risalire alla stessa, poichè this.avviso, all'interno del metodo, come Test.avviso, sempre all'interno o fuori dall'oggetto, non saranno utilizzabili, proprio grazie al fatto di essere private.


Rispondi quotando
se per variabili statiche si intende variabili di classe e non di istanza, esistono, sia variabili che metodi statici