Lo scopo di closures
è semplicemente quello di preservare lo stato; da qui il nome closure
: si chiude sullo stato. Per facilitare ulteriori spiegazioni, userò Javascript.
In genere hai una funzione
function sayHello(){
var txt="Hello";
return txt;
}
dove l'ambito delle variabili è associato a questa funzione. Quindi dopo l'esecuzione la variabile non txt
rientra nell'ambito. Non è possibile accedervi o utilizzarlo al termine dell'esecuzione della funzione.
Le chiusure sono costrutti linguistici, che consentono - come detto prima - di preservare lo stato delle variabili e prolungare così l'ambito di applicazione.
Questo potrebbe essere utile in diversi casi. Un caso d'uso è la costruzione di funzioni di ordine superiore .
In matematica e informatica, una funzione di ordine superiore (anche forma funzionale, funzionale o functor) è una funzione che svolge almeno una delle seguenti operazioni: 1
- accetta una o più funzioni come input
- genera una funzione
Un esempio semplice, ma certamente non troppo utile è:
makeadder=function(a){
return function(b){
return a+b;
}
}
add5=makeadder(5);
console.log(add5(10));
Si definisce una funzione makedadder
, che accetta un parametro come input e restituisce una funzione . Esiste una funzione esternafunction(a){}
e una interna. function(b){}{}
Inoltre definisci (implicitamente) un'altra funzione add5
come risultato della chiamata alla funzione di ordine superiore makeadder
. makeadder(5)
restituisce una funzione anonima ( interna ), che a sua volta accetta 1 parametro e restituisce la somma del parametro della funzione esterna e del parametro della funzione interna .
Il trucco è che mentre si restituisce la funzione interna , che fa l'effettiva aggiunta, a
viene preservato l'ambito del parametro della funzione esterna ( ). add5
ricorda che il parametro a
era 5
.
O per mostrare almeno un esempio in qualche modo utile:
makeTag=function(openTag, closeTag){
return function(content){
return openTag +content +closeTag;
}
}
table=makeTag("<table>","</table>")
tr=makeTag("<tr>", "</tr>");
td=makeTag("<td>","</td>");
console.log(table(tr(td("I am a Row"))));
Un altro caso d'uso comune è il cosiddetto IIFE = espressione della funzione immediatamente invocata. È molto comune in javascript falsificare le variabili dei membri privati. Ciò avviene tramite una funzione, che crea un ambito privato = closure
, poiché viene richiamata immediatamente dopo la definizione. La struttura è function(){}()
. Notare le parentesi ()
dopo la definizione. Ciò rende possibile usarlo per la creazione di oggetti con un modello di modulo rivelatore . Il trucco sta nel creare un ambito e restituire un oggetto, che ha accesso a questo ambito dopo l'esecuzione dell'IIFE.
L'esempio di Addi è simile al seguente:
var myRevealingModule = (function () {
var privateVar = "Ben Cherry",
publicVar = "Hey there!";
function privateFunction() {
console.log( "Name:" + privateVar );
}
function publicSetName( strName ) {
privateVar = strName;
}
function publicGetName() {
privateFunction();
}
// Reveal public pointers to
// private functions and properties
return {
setName: publicSetName,
greeting: publicVar,
getName: publicGetName
};
})();
myRevealingModule.setName( "Paul Kinlan" );
L'oggetto restituito ha riferimenti a funzioni (ad esempio publicSetName
), che a loro volta hanno accesso a variabili "private" privateVar
.
Ma questi sono casi d'uso più speciali per Javascript.
Quale compito specifico potrebbe svolgere un programmatore che potrebbe essere meglio servito da una chiusura?
Ci sono diverse ragioni per questo. Uno potrebbe essere, che è naturale per lui, dal momento che segue un paradigma funzionale . O in Javascript: è pura necessità fare affidamento su chiusure per aggirare alcune stranezze del linguaggio.