Utilité des fermetures (closures) ?


#1

Bonjour.
J’ai crois avoir assimilé le principe des fermetures ( closures), en tout cas en théorie. Mais je n’ai pas encore vraiment compris à quoi cela pouvait servir en pratique. Auriez-vous des exemples ? Des cas on ne peut pas faire sans ou au moins pour lesquels il est vraiment beaucoup plus simple d’utiliser des fermetures ?
Merci d’avance.
P.B.


#2

Bonjour @pbejian ,

Voici une liste d’exemples non exhaustifs de fonctionnalités qui ne seraient pas réalisables si toutes les fonctions en JavaScript (à l’exception de celles créées avec new Function()) n’étaient pas des fermetures.

Ceux-ci proviennent d’un des articles de mon blog intégralement consacré aux fermetures en général et ensuite spécifiquement aux fermetures en JavaScript.


Usage pratique des fermetures

Dans la pratique les fermetures permettent la création de structures élégantes, permettant la personnalisation de différents calculs définis par un argument fonctionnel. En voici des exemples non exhaustifs.

Argument fonctionnel

Voici un exemple avec la méthode sort des tableaux qui accepte en tant que premier paramètre un argument fonctionnel de « condition de tri » :

Code JavaScript

[1, 2, 3].sort(function (a, b) {
    // ... conditions de tri de votre choix
});

Voici un autre exemple avec la méthode find. Il est parfois intéressant d’utiliser des fonctions de recherche en utilisant des arguments fonctionnels définissant les conditions de recherche :

Code JavaScript

someCollection.find(function (element) {
    return element.someProperty === 'condition de recherche';
});

Association fonctionnelle

Voici un exemple de ce que l’on appel de l’association fonctionnelle (« mapping functionnals ») avec la méthode map d’un tableau. Celle-ci va associer à un nouveau tableau une valeur calculée à chaque élément :

Code JavaScript

[1, 2, 3].map(function (element) {
    return element * 2;
}); // `[2, 4, 6]`

Boucle de fonction

Il est aussi intéressant d’autres fois d’appliquer les fonctions fonctionnelles, par exemple, dans une méthode forEach qui applique des instructions pour chaque élément d’un tableau :

Code JavaScript

[1, 2, 3].forEach(function (element) {
    if (element % 2 !== 0) {
        console.log(element);
    }
});
// affiche `1`
// affiche `3`

apply et call

Au passage, les méthodes de fonction apply et call utilisent également des arguments fonctionnels. Nous avons déjà discuté de ces méthodes dans une note à propos de la valeur de this mais ici, nous allons voir leurs rôles avec les arguments fonctionnels ou fonctions appliquées en tant qu’argument (à une liste d’arguments avec apply et des positions d’argument avec call) :

Code JavaScript

(function () {
    console.log([].join.call(arguments, ';'));
}).apply(this, [1, 2, 3]);
// affiche `1;2;3`

Appel différés

Un autre point important des fermetures sont la possibilité des appels différés (« deferred calls ») :

Code JavaScript

var a = 10;
setTimeout(function () {
    console.log(a);
}, 1000);
// une seconde d'attente...
// ...puis affichaqe de `10`

Fonction de rappel

Plus simplement, un cas d’usage rependu des fermetures est celui des fonctions de rappel (« callback functions ») :

Code JavaScript

// ...
var x = 10;

xmlHttpRequestObject.onreadystatechange = function () {
  // la fonction de rappel est appelée en différé,
  // quand les données sont prêtes.
  // La variable `x` est ici disponible indépendamment
  // du fait que lorsque le contexte interne existe,
  // l'exécution du code externe est déjà fini.
  console.log(x); // `10`
};
// ...

Encapsulations privées

Les fermetures servent également à « masquer » des variables dans une portée encapsulante lors de l’exécution d’instructions :

Code JavaScript

var resitentEvil = {};

// initialisation
(function (object) {

    var veronica = 10;

    object.getVirus = function _getVirus() {
        return veronica;
    };

})(resitentEvil);

console.log(resitentEvil.getVirus()); // retourne la valeur `veronica` enfermée : `10`
console.log(veronica); // « erreur : `veronica` n'est pas défini(e) »