La clé pour comprendre les modèles de conception tels que IIFE est de se rendre compte qu’avant ES6, JavaScript ne comportait que la portée de la fonction (manquant donc la portée du bloc), en passant des valeurs par référence à l’intérieur des fermetures. Ce n’est plus le cas, car la version ES6 de JavaScript implémente la portée des blocs en utilisant les nouveaux mots-clés let
et const
.
Evaluation contextEdit
Un manque de portée de bloc signifie que les variables définies à l’intérieur (par exemple) d’une boucle for auront leur définition « hissée » en haut de la fonction englobante. L’évaluation d’une fonction qui dépend de variables modifiées par la fonction externe (y compris par itération) peut être difficile. Nous pouvons le voir sans boucle si nous mettons à jour une valeur entre la définition et l’appel de la fonction.
var v, getValue;v = 1;getValue = function () { return v; };v = 2;getValue(); // 2
Bien que le résultat puisse sembler évident lors de la mise à jour manuelle de v
, il peut produire des résultats involontaires lorsque getValue()
est défini dans une boucle.
Ci-après, la fonction passe v
comme argument et est appelée immédiatement, en préservant le contexte d’exécution de la fonction interne.
var v, getValue;v = 1;getValue = (function (x) { return function () { return x; };})(v);v = 2;getValue(); // 1
Ceci est équivalent au code suivant:
var v, getValue;v = 1;function f(x) { return function () { return x; };};getValue = f(v);v = 2;getValue(); // 1
Le JavaScript efficace de David Herman contient un exemple illustrant les problèmes de contexte d’évaluation à l’intérieur des boucles. Bien que l’exemple de Herman soit délibérément alambiqué, il découle directement du même manque de portée de bloc.
Établissement de variables privées et d’accessorsEdit
Les IIF sont également utiles pour établir des méthodes privées pour des fonctions accessibles tout en exposant certaines propriétés pour une utilisation ultérieure. L’exemple suivant provient du post d’Alman sur IIFEs.
// "counter" is a function that returns an object with properties, which in this case are functions.var counter = (function () { var i = 0; return { get: function () { return i; }, set: function (val) { i = val; }, increment: function () { return ++i; } };})();// These calls access the function properties returned by "counter".counter.get(); // 0counter.set(3);counter.increment(); // 4counter.increment(); // 5
Si nous tentons d’accéder à counter.i
à partir de l’environnement global, il ne sera pas défini, car il est inclus dans la fonction invoquée et n’est pas une propriété de counter
. De même, si nous tentons d’accéder à i
, cela entraînera une erreur, car nous n’avons pas déclaré i
dans l’environnement global.