Le but de closures
est simplement de préserver l' état; d'où le nom closure
- il ferme sur l'état. Pour faciliter l'explication, j'utilise le langage Javascript.
Vous avez généralement une fonction
function sayHello(){
var txt="Hello";
return txt;
}
où la portée de la ou des variables est liée à cette fonction. Donc, après exécution, la variable txt
sort de la portée. Il n'y a aucun moyen d'y accéder ou de l'utiliser une fois l'exécution de la fonction terminée.
Les fermetures sont des constructions de langage, qui permettent - comme dit précédemment - de conserver l’état des variables et donc de prolonger la portée.
Cela pourrait être utile dans différents cas. Un cas d'utilisation est la construction de fonctions d'ordre supérieur .
En mathématiques et en informatique, une fonction d'ordre supérieur (également forme fonctionnelle, fonctionnelle ou foncteur) est une fonction qui effectue au moins l'une des opérations suivantes: 1
- prend une ou plusieurs fonctions en entrée
- sort une fonction
Voici un exemple simple, mais pas trop utile:
makeadder=function(a){
return function(b){
return a+b;
}
}
add5=makeadder(5);
console.log(add5(10));
Vous définissez une fonction makedadder
qui prend un paramètre en entrée et renvoie une fonction . Il existe une fonction externefunction(a){}
et une fonction interne. En function(b){}{}
outre, vous définissez (implicitement) une autre fonction add5
à la suite de l'appel de la fonction d'ordre supérieur makeadder
. makeadder(5)
renvoie une fonction anonyme ( interne ), qui prend à son tour 1 paramètre et renvoie la somme du paramètre de la fonction externe et du paramètre de la fonction interne .
L' astuce est que, tout en renvoyant la fonction interne , qui effectue l'addition réelle, la portée du paramètre de la fonction externe ( a
) est préservée. add5
se souvient que le paramètre a
était 5
.
Ou pour montrer au moins un exemple 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"))));
Une autre utilisation courante est la dénommée IIFE = expression de fonction immédiatement appelée. Il est très fréquent en javascript pour faux variables membres privées. Cela se fait via une fonction, qui crée une portée privée = closure
, car elle est immédiatement après la définition invoquée. La structure est function(){}()
. Notez les crochets ()
après la définition. Cela permet de l'utiliser pour la création d'objets avec un motif de module révélateur . L'astuce consiste à créer une étendue et à renvoyer un objet, qui a accès à cette étendue après l'exécution de l'IIFE.
L'exemple d'Addi ressemble à ceci:
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'objet retourné a des références à des fonctions (par exemple publicSetName
), qui ont à leur tour accès à des variables "privées" privateVar
.
Mais ce sont des cas d'utilisation plus spéciaux pour Javascript.
Quelle tâche spécifique un programmeur effectuerait-il et qui pourrait être mieux servi par une fermeture?
Il y a plusieurs raisons à cela. On pourrait dire que c'est naturel pour lui, puisqu'il suit un paradigme fonctionnel . Ou en Javascript: il est simplement nécessaire de s’appuyer sur les fermetures pour contourner certaines bizarreries du langage.