Aller au contenu

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 :


Output appears here after Run.

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 :


Output appears here after Run.

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.


Output appears here after Run.

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.


Output appears here after Run.

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 :


Output appears here after Run.

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 :


Output appears here after Run.

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.


Output appears here after Run.

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.


javascript
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

  1. 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.
  2. 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.
  3. É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.
  4. Utiliser let et const : Préférez toujours let ou const à var pour garantir une portée correcte et éviter les comportements involontaires.
  5. 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?

Trouvez-vous cela utile?

Aperçu dual-run — comparez avec les routes Symfony en production.