Comment fonctionne les closures JavaScript ?

Le langage JavaScript possède un mécanisme de gestion des fonctions particulier appelé closure. Les closures se basent sur des fonctions dites de première classe. Ce sont des fonctions qui peuvent être stockées dans des variables, envoyées dans d'autres fonctions ou retournées comme résultat d'une fonction.

Lorsque vous utilisez le mot-clé function pour créer une fonction dans une fonction, alors vous êtes en train de créer une closure. Une closure est la pile de mémoire associée à une fonction. Cette pile mémorise les variables locales utilisées par la fonction au moment de sa destruction. Dans la plupart des langages de programmation, lorsque l'exécution d'une fonction se termine, les variables locales de la fonction sont détruites. Ce n'est pas le cas en JavaScript : elles sont sauvegardées dans une closure. L'utilisation des closures a surtout lieu quand une fonction transmet une fonction à une autre fonction ou retourne une fonction.

function direBonjour(nom)
{
var texte = 'Bonjour ' + nom; // Variable locale
var dire = function() { console.log(texte); }
return dire;
}
var maFonction = direBonjour('Jean');
maFonction(); // logs Bonjour Jean

Dans un autre langage, cet appel ne fonctionnerait pas car la variable locale texte aurait été détruite dès la fin de la fonction. Cela fonctionne en JavaScript grâce à l'existence de la closure dans laquelle les variables locales de la fonction ont été conservées. Il faut également savoir que les variables sauvegardées ne sont pas copiées, ce sont des références. Si après avoir déclaré une fonction utilisant une variable locale, vous modifiez ensuite cette variable locale avant de retourner la fonction, alors un appel de la fonction retournée montrera que la variable a été modifiée. C'est également le cas si vous créez une nouvelle variable après l'avoir utilisée dans la fonction retournée.

function multiplicationParDeux() {
// Variable locale utilisée pour démontrer la closure
var chiffre = 10;
var fonction = function() { console.log(chiffre * multiplicateur); }
chiffre = chiffre * 2;
var multiplicateur = 10;
return fonction;
}
var maFonction = multiplicationParDeux();
maFonction(); // Affiche 200 dans la console

Il faut également savoir qu'à chaque appel de la fonction, une nouvelle closure est créée à la place de l'ancienne.

var maFonction = multiplicationParDeux();
maFonction(); // Affiche 200 dans la console
maFonction(); // Affiche 400 dans la console
maFonction = multiplicationParDeux();
maFonction(); // Affiche 200 dans la console

Les closures fonctionnent sur plusieurs niveaux. Une closure est également créée quand on utilise la fonction eval(), qui permet d'évaluer un code JavaScript, dans une fonction.

JavaScript