Comprendre les fermetures JavaScript dans les boucles : exemples pratiques

JavaScript

Démêler les fermetures de boucles en JavaScript

Les développeurs JavaScript rencontrent souvent un comportement inattendu lorsqu'ils utilisent des fermetures à l'intérieur de boucles. Ce problème peut prêter à confusion, en particulier pour ceux qui sont nouveaux dans le concept de fermeture.

Dans cet article, nous explorerons des exemples pratiques qui illustrent les pièges courants et fournirons des solutions pour utiliser efficacement les fermetures dans les boucles, qu'il s'agisse d'écouteurs d'événements, de code asynchrone ou d'itérations sur des tableaux.

Commande Description
let Déclare une variable locale de portée bloc, en l'initialisant éventuellement à une valeur. Utilisé pour garantir que chaque itération de la boucle a sa propre portée.
const Déclare une constante nommée en lecture seule, de portée bloc. Utilisé pour créer une fonction ou une variable dont la valeur ne doit pas changer.
Promise Représente l’achèvement (ou l’échec) éventuel d’une opération asynchrone et sa valeur résultante.
setTimeout Appelle une fonction ou évalue une expression après un nombre spécifié de millisecondes.
addEventListener Attache un gestionnaire d'événements à un élément spécifié sans écraser les gestionnaires d'événements existants.
IIFE Expression de fonction immédiatement invoquée. Une fonction qui s'exécute dès qu'elle est définie. Utilisé pour créer des étendues locales dans des boucles.
for...in Itère sur les propriétés énumérables d’un objet, dans un ordre arbitraire.
for...of Parcourt les valeurs d'un objet itérable (comme un tableau ou une chaîne), dans un ordre spécifique.

Comprendre les fermetures JavaScript dans les boucles

Les scripts fournis dans les exemples précédents résolvent le problème courant des fermetures dans les boucles en JavaScript. Lorsque vous utilisez un déclaration dans une boucle, toutes les itérations partagent la même portée de fonction. C'est pourquoi, dans le premier exemple, le résultat est « Ma valeur : 3 » trois fois. La solution est d'utiliser , qui crée une portée de bloc qui conserve la valeur correcte pour chaque itération. Cette approche garantit que chaque itération a sa propre portée, préservant ainsi la valeur correcte lorsque la fonction est appelée. Le script montre comment changer la déclaration de à let corrige le problème et enregistre « Ma valeur : 0 », « Ma valeur : 1 » et « Ma valeur : 2 » comme prévu.

Pour le code asynchrone, le même problème de fermeture peut survenir. En utilisant et fonctions avec garantit que chaque appel asynchrone conserve la valeur d'itération correcte. Le script montre qu'en utilisant wait avec , chaque promesse résolue enregistre la valeur attendue. Les auditeurs d'événements peuvent également être confrontés à des problèmes similaires ; cependant, en encapsulant la fonction d'écoute dans un (Immediately Invoked Function Expression) permet de capturer la valeur correcte en créant une nouvelle portée pour chaque itération. L'utilisation de et for...of les boucles démontrent en outre l'importance de la portée dans les fermetures, montrant comment capturer correctement l'index et la valeur à l'aide de pour créer des étendues distinctes pour chaque itération de boucle.

Résoudre les problèmes de fermeture dans les boucles JavaScript avec let

JavaScript (ES6)

let funcs = [];
// Let's create 3 functions
for (let i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value:", i);
  };
}
for (let j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

Garantir des valeurs de fermeture correctes dans le code asynchrone

JavaScript (ES6)

const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));
for (let i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

Fermeture correcte dans les écouteurs d'événements à l'aide d'IIFE

JavaScript (ES6)

var buttons = document.getElementsByTagName("button");
// Let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  (function(i) {
    buttons[i].addEventListener("click", function() {
      // each should log its value.
      console.log("My value:", i);
    });
  })(i);
}

Fermeture correcte avec les boucles for...in et for...of

JavaScript (ES6)

const arr = [1, 2, 3];
const fns = [];
for (const i in arr) {
  fns.push(((i) => () => console.log("index:", i))(i));
}
for (const v of arr) {
  fns.push(((v) => () => console.log("value:", v))(v));
}
for (const n of arr) {
  const obj = { number: n };
  fns.push(((n, obj) => () => console.log("n:", n, "|", "obj:", JSON.stringify(obj)))(n, obj));
}
for (const f of fns) {
  f();
}

Explorer l'utilisation des fermetures dans les fonctions JavaScript avancées

Les fermetures sont un concept fondamental en JavaScript qui permet à une fonction d'accéder aux variables à partir de sa portée englobante, même après la fermeture de cette portée. Cette fonctionnalité est particulièrement puissante lors de la création de fonctions avancées telles que celles utilisées dans la mémorisation, le curry et la programmation fonctionnelle. Par exemple, la mémorisation exploite les fermetures pour mémoriser les résultats d'appels de fonctions coûteux et renvoyer le résultat mis en cache lorsque les mêmes entrées se reproduisent. En utilisant des fermetures, nous pouvons créer un code plus efficace et optimisé qui améliore les performances, en particulier dans les fonctions récursives telles que le calcul des séquences de Fibonacci.

Une autre utilisation avancée des fermetures consiste à créer des variables et des fonctions privées dans des objets JavaScript, en simulant des méthodes et des propriétés privées. Cette technique est souvent utilisée dans les modèles de module et les expressions de fonction immédiatement invoquées (IIFE) pour encapsuler les fonctionnalités et éviter de polluer la portée globale. De plus, les fermetures jouent un rôle crucial dans la gestion des événements et la programmation asynchrone, où elles aident à conserver l'état et le contexte au fil du temps. Comprendre et utiliser efficacement les fermetures peut améliorer considérablement vos compétences en programmation JavaScript et vous permettre d'écrire du code plus modulaire, réutilisable et maintenable.

  1. Qu'est-ce qu'une fermeture en JavaScript ?
  2. Une fermeture est une fonction qui conserve l'accès à sa portée lexicale, même lorsque la fonction est exécutée en dehors de cette portée.
  3. Pourquoi les fermetures se produisent-elles en boucles ?
  4. Les fermetures dans les boucles se produisent parce que la boucle crée des fonctions qui capturent la même référence de variable, ce qui entraîne un comportement inattendu si elle n'est pas gérée correctement.
  5. Comment pouvons-nous résoudre les problèmes de fermeture dans les boucles ?
  6. En utilisant au lieu de en boucles ou en utilisant (Expressions de fonction immédiatement invoquées) peuvent résoudre les problèmes de fermeture en créant une nouvelle portée pour chaque itération.
  7. Qu’est-ce qu’un IIFE ?
  8. Un est une fonction exécutée immédiatement après sa création, souvent utilisée pour créer une nouvelle portée et éviter les conflits de variables.
  9. Les fermetures peuvent-elles être utilisées dans la programmation asynchrone ?
  10. Oui, les fermetures sont essentielles dans la programmation asynchrone pour maintenir l'état et le contexte dans les opérations asynchrones telles que les promesses et les rappels.
  11. Qu'est-ce que la mémorisation et en quoi les fermetures sont-elles utiles ?
  12. La mémorisation est une technique d'optimisation permettant de mettre en cache les résultats d'appels de fonctions coûteux. Les fermetures aident en conservant l'accès au cache lors de plusieurs appels de fonction.
  13. Comment les fermetures aident-elles à la gestion des événements ?
  14. Les fermetures conservent l'état des variables nécessaires aux gestionnaires d'événements, garantissant qu'elles fonctionnent correctement lorsque l'événement est déclenché.
  15. Qu'est-ce que le modèle de module en JavaScript ?
  16. Le modèle de module utilise des fermetures pour créer des variables et des fonctions privées, encapsulant les fonctionnalités et évitant la pollution de portée globale.
  17. Les fermetures peuvent-elles simuler des méthodes privées en JavaScript ?
  18. Oui, les fermetures peuvent simuler des méthodes privées en gardant les variables et les fonctions accessibles uniquement dans la portée de la fonction où elles sont définies.

La maîtrise des fermetures en JavaScript, en particulier au sein des boucles, est cruciale pour écrire du code prévisible et efficace. En tirant parti , , et , les développeurs peuvent éviter les pièges courants et garantir une portée variable correcte. Cette compréhension améliore la capacité à gérer des tâches asynchrones et une programmation événementielle, conduisant finalement à des applications plus robustes.