Comment fonctionnent les fermetures JavaScript, en clair
JavaScript est un langage largement adopté que vous pouvez utiliser pour construire n’importe quoi, d’une simple page de destination à une application complète de qualité production. Au fur et à mesure de l’évolution de JavaScript et de la programmation en général, les développeurs se sont rendu compte que le paradigme de la programmation orientée objet (POO) n’est pas souhaitable pour la plupart des cas d’utilisation. La programmation fonctionnelle a émergé comme la solution à de nombreux points douloureux associés à la POO.
Les fermetures sont un sujet largement discuté dans le monde de la programmation fonctionnelle, mais elles sont souvent définies de manière vague et dans un jargon technique. Nous ferons de notre mieux ici pour expliquer le fonctionnement des closures JavaScript en termes simples.
À la fin de ce tutoriel, vous devriez comprendre :
- Comment identifier les fermetures
- Ce qu’est une fermeture et comment elle se comporte par rapport au contexte d’exécution et à la pile d’appels
- Common use cases for closures
Comprendre les fermetures JavaScript
Nous allons commencer par montrer à quoi ressemble une fermeture.
Essayez d’exécuter le code par vous-même. Techniquement, la fonction nommée makeCounter
renvoie une autre fonction appelée increment
. Cette fonction increment
a accès à la variable count
même après l’exécution de la fonction makeCount
. Une partie de la fermeture ici est la variable count
; elle est disponible pour la fonction increment
lorsqu’elle est définie, même après que makeCounter
ait terminé. L’autre partie est la fonction increment
.
Imaginez que vous avez une maison et un jardin qui l’entoure. Une fois que vous avez ouvert la porte du jardin et que vous l’avez fermée, vous ne pouvez plus l’ouvrir à nouveau – le jardin devient inaccessible. Vous avez faim et, heureusement, il y a un oranger et un pommier dans votre jardin. Vous prenez un petit sac, cueillez une orange et une pomme, et retournez dans votre maison. Rappelez-vous, vous ne pouvez pas ressortir à nouveau.
Maintenant, une fois que vous êtes à l’intérieur de votre maison, vous pouvez prendre l’orange ou la pomme dans le sac et la manger dès que vous avez à nouveau faim. Le petit sac dans cet exemple est la fermeture. Une fermeture contient toutes les variables et fonctions qui étaient à votre disposition lorsque vous étiez dans le jardin, même lorsque vous êtes à l’intérieur de la maison et que vous ne pouvez plus sortir.
Voyons comment cela se passe en code :
Puisque la variable fruits
est à la disposition de la fonction retournée lorsque makeFruitGarden
est exécutée, la variable fruits
et la fonction intérieure deviennent la fermeture. Chaque fois que consumeFruit
est exécuté, un fruit
– le dernier élément du tableau fruits
car pop()
est utilisé – est renvoyé. Une fois que les deux fruits auront été consommés/mangés, il ne restera plus rien à manger.
Comprendre la portée lexicale
Pour vraiment comprendre les closures, vous devez être familier avec le terme « portée ». La portée lexicale est un terme fantaisiste pour l’environnement actuel relatif à ce à quoi vous faites référence.
Dans l’exemple suivant, la portée de la variable nommée myName
est appelée la « portée globale ».
// global scopeconst myName = "John Doe"function displayName() { // local/function scope console.log(myName);};displayName()
Vous avez peut-être vu ce concept référencé lorsque vous avez lu comment var
n’est pas block-scopé et comment const
let
l’est. Il est important de noter qu’en JavaScript, une fonction crée toujours sa propre portée. C’est ce qu’on appelle la portée local
ou function
, comme le montre l’exemple de code.
Si vous avez été attentif, vous pensez peut-être que myName
et displayName
font partie d’une fermeture. Vous auriez raison ! Mais puisque la fonction et la variable ici existent dans la portée globale, il n’y a pas beaucoup de valeur à l’appeler une fermeture.
Il existe de nombreux types de portées en JavaScript, mais lorsqu’il s’agit de fermetures, il y a trois portées que vous devriez connaître :
- La portée globale est la portée par défaut où tout le monde vit. Pensez-y comme votre rue
- La portée externe de la fonction est la fonction qui renvoie une fonction. Elle a sa propre portée. Pensez-y comme votre jardin
- La portée de fonction interne/locale est la fonction retournée qui devient une fermeture. Pensez-y comme votre maison
Maintenant, plongeons dans quelques cas d’utilisation.
Cas d’utilisation courants pour les fermetures
Currying
Le curry de fonction est un autre concept puissant de la programmation fonctionnelle. Pour mettre en œuvre une fonction curry en JavaScript, vous utiliseriez des closures.
Currying une fonction peut être décrit comme la transformation d’une fonction et est exécuté comme ceci : add(1, 2, 3)
add(1)(2)(3)
.
function add(a) { return function(b) { return function(c) { return a + b + c; }; };};add(1)(2)(3) // returns 6
La fonction add
prend un seul argument puis renvoie deux fonctions imbriquées l’une après l’autre. Le but du currying est de prendre un tas d’arguments et de finir par obtenir une seule valeur.
Fonctions d’ordre supérieur
Le but d’une fonction d’ordre supérieur est de prendre une fonction en argument et de retourner un résultat. Les méthodes de tableau telles que map
et reduce
sont des exemples de fonctions d’ordre supérieur.
const arrayOfNumbers = ;const displayNumber = (num) => { console.log(num);}arrayOfNumbers.forEach(displayNumber)
La fonction d’ordre supérieur Array.prototype.forEach
accepte ici displayNumber
comme argument, puis l’exécute pour chaque élément de la arrayOfNumbers
. Si vous avez utilisé un framework d’interface utilisateur tel que Vue ou React, vous connaissez peut-être les composants d’ordre supérieur, qui sont essentiellement la même chose que les fonctions d’ordre supérieur.
Alors, quelle est la différence entre les fonctions d’ordre supérieur et le currying ? Alors qu’une fonction d’ordre supérieur prend une fonction comme argument renvoie une valeur, une fonction curry renvoie une fonction comme résultat, ce qui conduit éventuellement à une valeur.
Gestionnaires d’éléments DOM
C’est un modèle de conception commun souvent utilisé pour obtenir et définir les propriétés des éléments DOM. Dans l’exemple suivant, nous allons réaliser un gestionnaire d’éléments pour styliser les éléments.
makeStyleManager
renvoie un objet qui donne accès à deux fonctions, qui font partie d’une fermeture aux côtés des variables element
et currentStyles
. Même après que makeStyleManager
a fini de s’exécuter, les fonctions getStyle
et setStyle
ont accès aux variables.
Conclusion
Les closures JavaScript peuvent être difficiles à comprendre, même pour les développeurs ayant une expérience professionnelle à leur actif. Comprendre les fermetures fera finalement de vous un meilleur développeur.
Vous devriez maintenant être capable d’identifier une fermeture lorsqu’elle est utilisée dans une base de code qui semble bizarre ou qui n’a pas de sens. Les fermetures sont un concept critique dans la programmation fonctionnelle et j’espère que ce guide vous a aidé à faire un pas en avant dans votre voyage vers sa maîtrise.
LogRocket : Déboguer les erreurs JavaScript plus facilement en comprenant le contexte
Le débogage du code est toujours une tâche fastidieuse. Mais plus vous comprenez vos erreurs, plus il est facile de les corriger.
LogRocket vous permet de comprendre ces erreurs de manière nouvelle et unique. Notre solution de surveillance des frontaux suit l’engagement des utilisateurs avec vos frontaux JavaScript pour vous donner la possibilité de découvrir exactement ce que l’utilisateur a fait qui a conduit à une erreur.
LogRocket enregistre les journaux de la console, les temps de chargement des pages, les stacktraces, les demandes/réponses réseau lentes avec les en-têtes + les corps, les métadonnées du navigateur et les journaux personnalisés. Comprendre l’impact de votre code JavaScript ne sera jamais plus facile !
Essayez-le gratuitement.
Lectures complémentaires
- « Je n’ai jamais compris les fermetures JavaScript » – Un guide technique approfondi pour comprendre le fonctionnement d’une fermeture. Idéal pour quelqu’un qui veut comprendre les fermetures par rapport à la
ExecutionContext
, la pile d’appels, l’environnement lexical, etc. - Référence MDN pour les fermetures JavaScript – Un guide de référence rapide sur les fermetures (y compris certains pièges courants) au cas où vous auriez besoin de rafraîchir votre mémoire rapidement
- « Maîtrisez l’entretien JavaScript : What is a Closure ? » – Les closures expliquées par Eric Elliot ; idéal pour les développeurs qui ont une compréhension des concepts de programmation fonctionnelle
.