Closures en JavaScript

Closures en JavaScript

Cet article explique les closures en JavaScript.

YouTube Video

Closures en JavaScript

En JavaScript, une « closure » est l’un des concepts les plus importants et puissants. Une bonne compréhension des closures permet d’acquérir des connaissances utiles dans de nombreuses situations, comme le comportement et la portée des fonctions, ainsi que le traitement asynchrone et la gestion des événements en JavaScript. Ici, nous expliquerons en détail tout, de la définition de base des closures aux exemples concrets et à leurs applications.

Qu’est-ce qu’une closure ?

Une closure désigne le mécanisme par lequel une fonction peut accéder aux variables de sa portée de création, même lorsqu’elle est appelée en dehors de celle-ci. En utilisant les closures, il devient possible pour des fonctions de « se souvenir » en permanence des variables externes.

Les closures se composent des deux éléments suivants.

  1. Définition de la fonction (la fonction elle-même)

  2. Portée dans laquelle la fonction est définie (variables et autres fonctions situées en dehors de la fonction elle-même)

En JavaScript, les closures sont possibles car les fonctions ont la capacité d’accéder aux variables dans la portée où elles ont été créées.

Exemple de base

Voyons tout d’abord un exemple simple de closure. Dans le code suivant, outerFunction retourne une fonction appelée innerFunction. Le point important est que innerFunction peut accéder à la variable count définie dans la portée de outerFunction.

 1function outerFunction() {
 2    let count = 0;
 3
 4    function innerFunction() {
 5        count++;
 6        console.log(`Current count: ${count}`);
 7    }
 8
 9    return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3

Comment fonctionnent les closures

Comme on le voit dans l’exemple ci-dessus, count est conservé par innerFunction même après l’exécution de outerFunction. innerFunction peut continuer à accéder à la portée de outerFunction, et ainsi, count est mis à jour au sein de innerFunction. Ceci est le mécanisme de base d’une closure.

C’est innerFunction qui est affectée à la variable counter, et on constate que l’état de count est préservé même après l’exécution de outerFunction. Cela s’explique par le fait que JavaScript « se souvient » en permanence de la portée au moment de la définition de la fonction.

Application : closures comme variables privées

Les closures peuvent être utilisées comme des « variables privées » en programmation orientée objet. Normalement, en JavaScript, les propriétés d’un objet sont accessibles directement de l’extérieur, mais grâce aux closures, on peut empêcher toute manipulation directe de variables situées dans la portée d’une fonction.

Dans l’exemple suivant, la fonction createCounter utilise une closure pour créer un compteur, et retourne un compteur avec une variable privée count.

 1function createCounter() {
 2    let count = 0;
 3
 4    return {
 5        increment: function() {
 6            count++;
 7            console.log(`Count: ${count}`);
 8        },
 9        decrement: function() {
10            count--;
11            console.log(`Count: ${count}`);
12        },
13        getCount: function() {
14            return count;
15        }
16    };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1

Dans cet exemple, count appartient à la portée de la fonction createCounter, et ne peut donc pas être accédée directement de l’extérieur. Cependant, elle peut être manipulée à l’aide des méthodes increment et decrement. De cette manière, grâce aux closures, il est possible d’intégrer le concept de variables privées en JavaScript.

Exemples pratiques de closures

Association avec les fonctions de rappel (callbacks)

Les closures sont souvent utilisées en combinaison avec les callbacks pour gérer le traitement asynchrone. Prenons par exemple l’utilisation d’un minuteur (timer).

 1function startTimer(duration) {
 2    let timeLeft = duration;
 3
 4    function countdown() {
 5        console.log(`Time left: ${timeLeft} seconds`);
 6        timeLeft--;
 7
 8        if (timeLeft >= 0) {
 9            setTimeout(countdown, 1000);
10        }
11    }
12
13    countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds

Dans cet exemple, la fonction countdown accède à la variable timeLeft à l’intérieur de la portée de startTimer. Ainsi, les closures s’avèrent très utiles lors du traitement asynchrone (comme les timers), car elles conservent l’état des variables au fil du temps.

Gestionnaires d’événements

Les closures sont également pratiques lors de la configuration de gestionnaires d’événements. Dans l’exemple suivant, une closure permet d’enregistrer le nombre de clics sur un bouton.

 1function setupClickCounter(buttonId) {
 2    let clickCount = 0;
 3
 4    const button = document.getElementById(buttonId);
 5    button.addEventListener('click', function() {
 6        clickCount++;
 7        console.log(`Button clicked ${clickCount} times`);
 8    });
 9}
10
11setupClickCounter('myButton');

Dans ce cas, clickCount augmente à chaque clic, et sa valeur est conservée. En utilisant des closures, il devient possible d’attribuer un compteur indépendant à chaque bouton.

Conclusion

Les closures symbolisent la flexibilité et la puissance de JavaScript. Elles conservent des variables enfermées dans une portée de fonction et permettent d’agir sur ces variables via des fonctions accessibles de l’extérieur. En comprenant et en utilisant ce mécanisme, vous pourrez acquérir des techniques plus avancées en JavaScript.

Les closures s’appliquent à de nombreuses situations, y compris la gestion des événements, le traitement asynchrone et même des pseudo-implémentations de la programmation orientée objet.

Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.

YouTube Video