| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Closures | [Back] [Original] |
Get to know MDN better
Cette page a t traduite partir de l'anglais par la communaut. Vous pouvez contribuer en rejoignant la communaut francophone sur MDN Web Docs.
Une fermeture est la paire forme d'une fonction et des rfrences son tat environnant (l'environnement lexical). En d'autres termes, une fermeture donne accs la porte d'une fonction externe partir d'une fonction interne (on dit aussi que la fonction capture son environnement ). En JavaScript, une fermeture est cre chaque fois qu'une fonction est cre.
Dans l'exemple suivant :
function init() {
var nom = "Mozilla"; // nom est une variable locale de init
function afficheNom() {
// afficheNom est une fonction interne de init
console.log(nom); // ici nom est une variable libre (dfinie dans la fonction parente)
}
afficheNom();
}
init();
La fonction init cr une variable locale nom et une fonction interne afficheNom. La fonction interne est seulement visible de l'intrieur de init. Contrairement init, afficheNom ne possde pas de variable locale propre, mais elle utilise la variable nom de la fonction parente (ceci dit afficheNom pourrait utiliser ses variables locales propres si elle en avait).
Vous pouvez excuter le code sur cette page pour voir son fonctionnement. On a ici un exemple de porte lexicale : en JavaScript, la porte d'une variable est dfinie par son emplacement dans le code source (elle apparat de faon lexicale), les fonctions imbriques ont ainsi accs aux variables dclares dans les portes parentes.
tudions l'exemple suivant :
function creerFonction() {
var nom = "Mozilla";
function afficheNom() {
console.log(nom);
}
return afficheNom;
}
var maFonction = creerFonction();
maFonction();
Ce code produit le mme rsultat que l'appel init() tudi prcdemment : "Mozilla" est affich dans la console. L'intrt de ce code est qu'une fermeture contenant la fonction afficheNom() est renvoye par la fonction parente, avant d'tre excute.
Le code continue fonctionner, ce qui peut paratre contre-intuitif au regard de la syntaxe utilise. Usuellement, les variables locales d'une fonction n'existent que pendant l'excution d'une fonction. Une fois que creerFonction() a fini son excution, on aurait pu penser que la variable nom n'est plus accessible. Cependant, le code fonctionne : en JavaScript, la variable est donc accessible d'une certaine faon.
L'explication est la suivante : maFonction est une fermeture. La fermeture combine la fonction afficheNom et son environnement. Cet environnement est compos de toutes les variables locales accessibles (dans la porte) la cration de la fermeture. Ici maFonction est une fermeture qui contient la fonction afficheNom et une rfrence la variable var nom = "Mozilla" qui existait lorsque la fermeture a t cre. L'instance de afficheNom conserve une rfrence son environnement lexical, dans lequel nom existe. Pour cette raison, lorsque maFonction est invoque, la variable nom reste disponible et "Mozilla" est transmis console.log.
Voici un exemple un peu plus intressant, une fonction ajouterA :
function ajouterA(x) {
return function (y) {
return x + y;
};
}
var ajouter_5 = ajouterA(5);
var ajouter_10 = ajouterA(10);
console.log(ajouter_5(2)); // 7
console.log(ajouter_10(2)); // 12
On dfinit une fonction ajouterA(x) avec un seul argument x et qui renvoie une fonction anonyme. La fonction anonyme a un seul argument y, et renvoie la somme de x et y.
La fonction ajouterA permet de crer des fermetures qui font la somme de leur argument et d'un nombre fix. Dans l'exemple ci-dessus, on cre ajouter_5 et ajouter_10. Elles partagent la mme fonction, mais des environnements diffrents. Dans ajouter_5, x vaut 5 ; dans ajouter_10, x vaut 10.
On a vu la thorie dcrivant les fermetures. Est-ce qu'elles sont utiles pour autant ? Une fermeture permet d'associer des donnes (l'environnement) avec une fonction qui agit sur ces donnes. On peut faire un parallle avec la programmation oriente objet, car les objets permettent d'associer des donnes (les proprits) avec des mthodes.
Ainsi, on peut utiliser une fermeture pour tout endroit o on utiliserait un objet et ce avec une seule mthode.
Beaucoup de code JavaScript utilis sur le Web gre des vnements : on dfinit un comportement, puis on l'attache un vnement dclench par l'utilisateur (tel un clic ou une frappe clavier). Notre code est gnralement une fonction de rappel (ou callback) excute en rponse l'vnement.
Voici un exemple concret : si on souhaite ajouter des boutons une page afin d'ajuster la taille du texte, on pourrait dfinir la taille de police de l'lment body en pixels, et celles des autres lments relativement cette premire taille grce l'unit em :
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.2em;
}
Les boutons vont ensuite changer la taille de la police de l'lment body, ce changement tant rpercut aux autres lments grce aux units relatives.
Voici le code JavaScript qui correspond :
function fabriqueRedimensionneur(taille) {
return function () {
document.body.style.fontSize = taille + "px";
};
}
var taille12 = fabriqueRedimensionneur(12);
var taille14 = fabriqueRedimensionneur(14);
var taille16 = fabriqueRedimensionneur(16);
taille12, taille14, et taille16 sont dsormais des fermetures qui peuvent, respectivement, redimensionner le texte de l'lment body 12, 14, ou 16 pixels. On peut les attacher aux boutons de la faon suivantes :
document.getElementById("taille-12").onclick = taille12;
document.getElementById("taille-14").onclick = taille14;
document.getElementById("taille-16").onclick = taille16;
<a href="#" id="taille-12">12</a>
<a href="#" id="taille-14">14</a>
<a href="#" id="taille-16">16</a>
Vous pouvez excuter le code correspondant sur JSFiddle.
Certains langages de programmation, comme Java, permettent d'avoir des mthodes prives, c'est--dire qu'on ne peut les utiliser qu'au sein de la mme classe.
JavaScript ne permet pas de faire cela de faon native. En revanche, on peut muler ce comportement grce aux fermetures. Les mthodes prives ne sont pas seulement utiles en termes de restriction d'accs au code, elles permettent galement de grer un espace de nom (namespace) global qui isole les mthodes secondaires de l'interface publique du code ainsi rendu plus propre.
Voici comment dfinir une fonction publique accdant des fonctions et des variables prives en utilisant des fermetures. Cette faon de procder est galement connue comme le patron de conception module :
var compteur = (function () {
var compteurPrive = 0;
function changeValeur(val) {
compteurPrive += val;
}
return {
increment: function () {
changeValeur(1);
},
decrement: function () {
changeValeur(-1);
},
valeur: function () {
return compteurPrive;
},
};
})();
console.log(compteur.valeur()); /* Affiche 0 */
compteur.increment();
compteur.increment();
console.log(compteur.valeur()); /* Affiche 2 */
compteur.decrement();
console.log(compteur.valeur()); /* Affiche 1 */
Il y a beaucoup de diffrences par rapport aux exemples prcdents. Au lieu de retourner une simple fonction, on retourne un objet anonyme qui contient 3 fonctions. Et ces 3 fonctions partagent le mme environnement. L'objet retourn est affect la variable compteur, et les 3 fonctions sont alors accessibles sous les noms compteur.increment, compteur.decrement, et compteur.valeur.
L'environnement partag vient du corps de la fonction anonyme qui est excute ds sa dfinition complte (on parle d'expression de fonction immdiatement invoque, abrg en anglais en IIFE). L'environnement en question contient deux lments privs : une variable compteurPrive et une fonction changeValeur. Aucun de ces deux lments ne peut tre utilis en dehors de la fonction anonyme ; seules les trois fonctions renvoyes par la fonction anonyme sont publiques.
Ces trois fonctions publiques sont des fermetures qui partagent le mme environnement. Grce la porte lexicale, chacune a accs compteurPrive et changeValeur.
On remarquera qu'on dfinit une fonction anonyme qui cre un compteur puis qu'on l'appelle immdiatement pour assigner le rsultat la variable compteur. On pourrait stocker cette fonction dans une variable puis l'appeler plusieurs fois afin de crer plusieurs compteurs.
var creerCompteur = function () {
var compteurPrive = 0;
function changeValeur(val) {
compteurPrive += val;
}
return {
increment: function () {
changeValeur(1);
},
decrement: function () {
changeValeur(-1);
},
valeur: function () {
return compteurPrive;
},
};
};
var compteur1 = creerCompteur();
var compteur2 = creerCompteur();
console.log(compteur1.valeur()); /* Affiche 0 */
compteur1.increment();
compteur1.increment();
console.log(compteur1.valeur()); /* Affiche 2 */
compteur1.decrement();
console.log(compteur1.valeur()); /* Affiche 1 */
console.log(compteur2.valeur()); /* Affiche 0 */
Ici on peut voir que chacun des deux compteurs est indpendant de l'autre. Un nouvel environnement est instanci chaque appel creerCompteur().
L'utilisation de fermetures permet ainsi de bnficier de certains concepts lis la programmation oriente objet comme l'encapsulation et la dissimulation de donnes.
Une fermeture s'inscrit dans trois portes :
On peut oublier parfois, dans le cas de fonctions imbriques, qu'une fonction accde la porte de la fonction extrieure qui l'invoque. Ainsi, on peut avoir des enchanements de portes qui permette une fermeture d'accder la porte de la fonction englobante mais galement celles des fonctions qui englobent cette dernire. Voyons le code qui suit :
// Porte globale
var e = 10;
function somme(a) {
return function (b) {
return function (c) {
// Porte des autres fonctions (externes)
return function (d) {
// Porte locale
return a + b + c + d + e;
};
};
};
}
console.log(somme(1)(2)(3)(4)); // affiche 20
// On peut aussi crire ceci sans fonction anonyme :
// Porte globale
var e = 10;
function somme(a) {
return function somme2(b) {
return function somme3(c) {
// Porte des autres fonctions
return function somme4(d) {
// Porte locale
return a + b + c + d + e;
};
};
};
}
var somme2 = somme(1);
var somme3 = somme2(2);
var somme4 = somme3(3);
var resultat = somme4(4);
console.log(resultat); // affiche 20
Dans l'exemple qui prcde, on a une suite de fonctions imbriques dont chacune accde la porte des fonctions extrieures. Dans ce contexte, on peut dire que les fermetures ont accs l'ensemble des portes des fonctions extrieures.
Avant que le mot cl let ne soit introduit avec ECMAScript 2015, un problme se posait frquemment lorsqu'on manipulait des fermetures au sein d'une boucle. Par exemple :
<p id="aide">Des aides seront affiches ici</p>
<p>E-mail : <input type="text" id="email" name="email" /></p>
<p>Nom : <input type="text" id="nom" name="nom" /></p>
<p>ge : <input type="text" id="ge" name="ge" /></p>
function afficherAide(aide) {
document.getElementById("aide").innerHTML = aide;
}
function preparerAide() {
var texteAide = [
{ id: "email", aide: "Votre adresse e-mail" },
{ id: "nom", aide: "Vos prnom et nom" },
{ id: "ge", aide: "Votre ge (plus de 16 ans requis)" },
];
for (var i = 0; i < texteAide.length; i++) {
var item = texteAide[i];
document.getElementById(item.id).onfocus = function () {
afficherAide(item.aide);
};
}
}
preparerAide();
Vous pouvez essayer ce code sur JSFiddle.
Lorsqu'on essaie ce code, on s'aperoit qu'il ne fonctionne pas exactement comme on le souhaitait : en effet, quel que soit le champ sur lequel on se situe, c'est toujours le message d'aide concernant l'ge qui s'affiche.
La cause de ce problme est que les fonctions attaches onfocus sont des fermetures qui partagent le mme environnement. chaque itration de boucle, l'environnement de la fermeture cre contient une rfrence sur la mme instance de la variable item. Ainsi, lorsque la fonction de rappel de onfocus est excute, la boucle a dj t effectue entirement, et la variable item partage par les trois fermetures pointe sur le dernier lment de texteAide.
Une solution consiste utiliser plus de fermetures et appliquer une fabrique de fonction comme on a vu prcdemment :
function afficheAide(aide) {
document.getElementById("aide").innerHTML = aide;
}
function creerCallbackAide(aide) {
return function () {
afficheAide(aide);
};
}
function prepareAide() {
var texteAide = [
{ id: "email", aide: "Votre adresse e-mail" },
{ id: "nom", aide: "Votre prnom et nom" },
{ id: "ge", aide: "Your age (you must be over 16)" },
];
for (var i = 0; i < texteAide.length; i++) {
var item = texteAide[i];
document.getElementById(item.id).onfocus = creerCallbackAide(item.aide);
}
}
prepareAide();
Voici une autre solution qui permet de ne pas utiliser plus de fermetures :
function afficheAide(aide) {
document.getElementById("aide").innerHTML = aide;
}
function prepareAide() {
var texteAide = [
{ id: "email", aide: "Votre adresse e-mail" },
{ id: "nom", aide: "Votre prnom et nom" },
{ id: "ge", aide: "Votre ge (vous devez tre majeur)" },
];
for (var i = 0; i < texteAide.length; i++) {
let item = texteAide[i];
document.getElementById(item.id).onfocus = function () {
afficheAide(item.aide);
};
}
}
prepareAide();
Dans ce fragment de code, nous avons utilis let au lieu de var afin que chaque fermeture soit lie avec les variables de bloc.
Vous pouvez essayer ce code sur JSFiddle.
Autrement, on aurait pu utiliser forEach() afin de parcourir le tableau texteAide et attacher un gestionnaire d'vnement sur chaque <div> :
function afficheAide(aide) {
document.getElementById("aide").innerHTML = aide;
}
function prepareAide() {
var texteAide = [
{ id: "email", aide: "Votre adresse e-mail" },
{ id: "nom", aide: "Votre prnom et nom" },
{ id: "ge", aide: "Votre ge (vous devez tre majeur)" },
];
texteAide.forEach(function (texte) {
document.getElementById(texte.id).onfocus = function () {
afficheAide(texte.help);
};
});
}
prepareAide();
Il est mal avis de crer des fonctions imbriques et des fermetures sans utilit. En effet, cela peut dgrader les performances en termes de vitesse d'excution et de consommation de mmoire.
Quand, par exemple, on cre un nouvel objet, les mthodes devraient tre associes au prototype de l'objet et non pas dfinies dans le constructeur de l'objet. De cette faon, on vite que les mthodes soient rassignes chaque fois qu'un nouvel objet est cr.
Voici un exemple de la mauvaise faon de procder :
function MonObjet(nom, message) {
this.nom = nom.toString();
this.message = message.toString();
this.getNom = function () {
return this.nom;
};
this.getMessage = function () {
return this.message;
};
}
Le fragment de code prcdent ne tire pas parti des avantages des fermetures. Il pourrait tre mieux crit ainsi :
function MonObjet(nom, message) {
this.nom = nom.toString();
this.message = message.toString();
}
MonObjet.prototype = {
getNom: function () {
return this.nom;
},
getMessage: function () {
return this.message;
},
};
Cependant, redfinir le prototype est dconseill, donc encore meilleur serait d'ajouter les mthodes :
function MonObjet(nom, message) {
this.nom = nom.toString();
this.message = message.toString();
}
MonObjet.prototype.getNom = function () {
return this.nom;
};
MonObjet.prototype.getMessage = function () {
return this.message;
};
Les deux derniers exemples permettent de voir que le prototype hrit est partag par tous les objets construits et que les mthodes n'ont pas besoin d'tre reconstruites pour chaque cration d'objet. Veuillez consulter la page sur le modle objet JavaScript en dtails pour plus d'informations.
Cette page a t modifie le 7 sept. 2025 par les contributeurices du MDN.
Certaines parties de ce contenu sont protges par le droit d'auteur 19982026 des contributeurs individuels de mozilla.org. Contenu disponible sous une licence Creative Commons.
| Web Proxy Viewer | New URL | Original Page |