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.
Confidentialité des données / Encapsulation des données
// 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;
Application partielle
// 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');
}
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 :
var.{...}) 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.
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;
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;
}