Fe

Fermetures en JavaScript

1 exercice

À propos de Fermetures

Les closures sont un patron de programmation en JavaScript qui permet d'utiliser des variables d'une portée lexicale externe à l'intérieur d'un bloc de code imbriqué. JavaScript prend en charge les closures de manière transparente, et on les utilise souvent sans savoir ce que c'est.

// Top-level declarations are global-scope
const dozen = 12;

// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
  return dozen * n;
}

Le nom closure vient historiquement du λ-calcul et a été popularisé par scheme (source) pour désigner les liaisons de variables ouvertes et fermées d'une fonction.

Pourquoi utiliser des closures en JavaScript

  1. Confidentialité des données / Encapsulation des données

    • Contrairement à d'autres langages, en 2020, il n'existait aucun moyen de déclarer des variables privées. Les closures permettent donc d'émuler efficacement des variables privées (une proposition visant à introduire une notation pour les variables privées existait, et elle est peut-être devenue standard le temps que tu lises ces lignes).
    // Consider this function:
    
    const saveNumber = (number) => {
      // The saved value is unaccessible by the outer lexical scope.
      const value = number;
    
      // We can provide access to the primitive value with a function, but the original will never change
      return () => value;
    };
    
    // Attempting to set the variable outside of its lexical scope results in an error
    value = 42;
    
  2. Application partielle

    • Une fonction peut renvoyer une fonction, et lorsqu'une fonction renvoyée utilise l'argument de la fonction qui l'a créée, c'est un exemple d'utilisation d'une closure pour réaliser une application partielle. On parle parfois de currying d'une fonction.
    // The arguments are applied one-by-one, using closures to arrive at the final result
    function partialBuildUri(scheme) {
      return function (domain) {
        return function (path) {
          return `${scheme}://${domain}/${path}`;
        };
      };
    }
    
    // A function could apply them all at once.
    function buildUri(scheme, domain, path) {
      return partialBuildUri(scheme)(domain)(path);
    }
    
    // Or apply a few to create a flexible system of functions for reuse.
    function buildHttpsExercismUri(path) {
      return partialBuildUri('https')('exercism.org');
    }
    

La portée lexicale des variables

Dans n'importe quel langage de programmation, les Closures sont étroitement liées à la portée des variables. En JavaScript, il existe 3 types de portée lexicale pour les variables :

  1. Portée globale : les variables déclarées en dehors des fonctions et des blocs.
  2. Portée de fonction : les variables déclarées à l'intérieur d'une fonction avec le mot-clé var.
  3. Portée de bloc : les variables déclarées à l'intérieur d'un bloc ({...}) avec les mots-clés let et const.

En pratique, une closure apparaît souvent quand une fonction (ou un bloc) utilise une variable d'une portée externe. En JavaScript, c'est pris en charge de manière transparente, donc les closures sont souvent utilisées sans référence explicite.

Portée de fonction

Le mot-clé var définit une variable à portée de fonction. Cela signifie que les variables définies avec var sont accessibles partout dans la fonction où elles sont définies, ainsi que dans toute portée lexicale imbriquée (qu'elle soit de fonction ou de bloc).

{
  var five = 5;
}

// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;

Portée de bloc

Les mots-clés let et const définissent des variables à portée de bloc. let définit une variable modifiable, dont la valeur peut être définie plusieurs fois et qui peut être déclarée sans être initialisée. const définit une variable qui doit être initialisée au moment de sa déclaration, et dont la valeur ne peut plus changer ensuite. Si la variable const contient une valeur primitive, elle ne peut pas être modifiée. Si la variable const contient une valeur de référence, comme un tableau ou un objet, la référence ne peut pas changer, mais le contenu du tableau peut être modifié.

Prenons ce bloc :

// 'two' is defined at the top-level, therefore available to the global-scope
const two = 2;

{
  // This succeeds, as 'two' is available from the outer lexical scope
  const oneLess = two - 1;
}

// This throws an error because oneLess is not defined outside of the previous inner lexical scope
console.log(oneLess);

Même si on peut utiliser des accolades ({...}) librement pour créer des blocs, on les rencontre le plus souvent autour d'instructions if, de fonctions et de classes.

const PI = 3.14;

// This function uses a closure for the value of PI (π)
function areaOfCircle(radius) {
  return PI * radius * radius;
}
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet

Apprends Fermetures