Closures
Comprendre les closures en JavaScript
En JavaScript, les closures sont un concept fondamental et puissant qui permet de créer des fonctions avec des données conservées de leur environnement lexical. Ce guide propose une exploration approfondie des closures, avec des explications détaillées et des exemples de code pratiques pour consolider votre compréhension.
Qu’est-ce qu’une closure ?
Une closure est la combinaison d’une fonction et de l’environnement lexical dans lequel cette fonction a été déclarée. Cet environnement se compose de toutes les variables locales qui étaient dans le champ d’application au moment où la closure a été créée.
Exemple de closure
Considérez l’exemple suivant :
Dans cet exemple, greetByName est une closure. Elle capture les variables greeting et name de la portée de la fonction greet.
Lorsque la fonction greet est appelée avec l’argument 'John', elle crée une variable locale greeting et une fonction greetByName. La fonction greet renvoie ensuite la fonction greetByName. Même après la fin de l’exécution de la fonction greet, la fonction greetByName renvoyée a toujours accès aux variables greeting et name. Cela s’explique par le fait que greetByName est une closure, ce qui signifie qu’elle se souvient de l’environnement dans lequel elle a été créée.
Pourquoi utiliser des closures ?
Les closures permettent l’encapsulation des données et la création de variables privées. Elles permettent aux fonctions de conserver l’accès aux variables de leur portée englobante, même après la fin de l’exécution de cette portée.
Créer une closure de base
Considérez l’exemple suivant :
Lorsque outerFunction est invoquée, elle crée outerVariable et innerFunction. Elle renvoie ensuite innerFunction. La innerFunction renvoyée conserve l’accès à outerVariable même après la fin de l’exécution de outerFunction.
Cas d’utilisation pratiques des closures
Confidentialité des données
Les closures peuvent être utilisées pour créer des données privées auxquelles on ne peut pas accéder depuis la portée globale.
Dans cet exemple, count est une variable privée qui ne peut être consultée et modifiée que par la fonction anonyme renvoyée. Chaque fois que la fonction est appelée, elle incrémente et renvoie la valeur mise à jour de count.
Fabriques de fonctions
Les closures peuvent être utilisées pour créer des fabriques de fonctions qui génèrent des fonctions spécialisées.
Ici, createMultiplier génère des fonctions qui multiplient un nombre donné par un multiplier spécifié. Chaque fonction renvoyée conserve l’accès à la valeur multiplier via la closure.
Closures dans les boucles
Les closures peuvent être délicates lorsqu’elles sont utilisées à l’intérieur de boucles. Considérez l’exemple suivant :
Dans ce code, la boucle se termine, puis les trois rappels setTimeout s’exécutent, affichant la valeur de i, qui est 4 après la fin de la boucle. Cela se produit parce que var a une portée de fonction.
Pour corriger cela, utilisez let, qui a une portée de bloc :
INFO
Utilisez toujours let ou const au lieu de var pour éviter les problèmes de portée et garantir que les variables ont la portée appropriée.
Closures et gestion de la mémoire
Les closures peuvent provoquer des fuites de mémoire si elles ne sont pas utilisées correctement. Comme les closures conservent des références à leur portée externe, les variables inutilisées peuvent rester en mémoire plus longtemps que nécessaire.
WARNING
Faites attention à l’utilisation de la mémoire lors de la création de closures. Assurez-vous que les closures ne capturent pas inutilement de gros objets ou des éléments DOM afin d’éviter les fuites de mémoire.
Modèles avancés de closures
Modèle de module
Le modèle de module exploite les closures pour créer des membres privés et publics au sein d’une fonction.
Dans cet exemple, CounterModule est une expression de fonction immédiatement invoquée (IIFE) qui renvoie un objet avec des méthodes publiques (increment et reset). La variable count reste privée et ne peut pas être consultée directement.
Closures dans les frameworks JavaScript modernes
Les closures sont particulièrement importantes dans les frameworks JavaScript modernes comme React. Dans React, les closures aident à gérer l’état et les effets secondaires dans les composants fonctionnels.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(prevCount => prevCount + 1);
}
return (
<div>
<p>{count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}Dans cet exemple, useState est utilisé pour créer une variable d’état count et une fonction setCount pour la mettre à jour. La fonction increment forme une closure, capturant setCount et count depuis la portée du composant. Remarque : dans React, les closures peuvent parfois capturer un état obsolète si les dépendances ne sont pas correctement gérées dans des hooks comme useEffect.
INFO
Entraînez-vous à créer et à utiliser des closures dans différents contextes pour bien comprendre leur potentiel et leurs limites. Elles constituent un outil essentiel dans la boîte à outils de tout développeur JavaScript.
Bonnes pratiques pour utiliser les closures
- Limiter la portée : Évitez de créer des closures dans des boucles ou des structures profondément imbriquées, sauf si cela est nécessaire, afin d’éviter les fuites de mémoire et les problèmes de performance.
- Réduire au minimum les variables capturées : Ne capturez dans la closure que les variables dont vous avez besoin afin de réduire la consommation de mémoire.
- Éviter les captures volumineuses : Ne capturez pas de gros objets ou des éléments DOM dans les closures afin d’éviter une rétention mémoire inutile.
- Utiliser
letetconst: Préférez toujoursletouconstàvarpour garantir une portée correcte et éviter les comportements involontaires. - Nettoyer : Lorsque c’est possible, nettoyez les références capturées par les closures afin d’éviter les fuites de mémoire, en particulier dans les applications de longue durée.
Conclusion
Les closures sont une fonctionnalité puissante de JavaScript, permettant la confidentialité des données, les fabriques de fonctions et des modèles avancés comme les modules. Comprendre et utiliser efficacement les closures peut conduire à un code plus robuste et plus maintenable. En maîtrisant les closures, vous améliorerez votre capacité à écrire un code JavaScript efficace, sécurisé et propre.
Practice
What are closures in JavaScript?