Question

J'ai posé une question sur le curry et des fermetures ont été mentionnées.Qu'est-ce qu'une fermeture ?Quel est le rapport avec le curry ?

Était-ce utile?

La solution

Portée variable

Lorsque vous déclarez une variable locale, cette variable a une portée.Généralement, les variables locales n'existent que dans le bloc ou la fonction dans lequel vous les déclarez.

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

Si j'essaie d'accéder à une variable locale, la plupart des langues la rechercheront dans la portée actuelle, puis dans les portées parents jusqu'à ce qu'elles atteignent la portée racine.

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

Lorsqu'un bloc ou une fonction est terminé, ses variables locales ne sont plus nécessaires et sont généralement saturées de mémoire.

C’est ainsi que nous nous attendons normalement à ce que les choses fonctionnent.

Une fermeture est une portée de variable locale persistante

Une fermeture est une portée persistante qui conserve les variables locales même après que l'exécution du code soit sortie de ce bloc.Les langages prenant en charge la fermeture (tels que JavaScript, Swift et Ruby) vous permettront de conserver une référence à une portée (y compris ses portées parents), même après la fin de l'exécution du bloc dans lequel ces variables ont été déclarées, à condition de conserver une référence. à ce bloc ou à cette fonction quelque part.

L'objet scope et toutes ses variables locales sont liés à la fonction et persisteront aussi longtemps que cette fonction persistera.

Cela nous donne la portabilité des fonctions.Nous pouvons nous attendre à ce que toutes les variables qui étaient dans la portée lorsque la fonction a été définie pour la première fois soient toujours dans la portée lorsque nous appellerons la fonction ultérieurement, même si nous appelons la fonction dans un contexte complètement différent.

Par exemple

Voici un exemple très simple en JavaScript qui illustre ce point :

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}

var fnc = outer(); // execute outer to get inner 
fnc();

Ici, j'ai défini une fonction dans une fonction.La fonction interne a accès à toutes les variables locales de la fonction externe, y compris a.La variable a est dans le cadre de la fonction interne.

Normalement, lorsqu'une fonction se termine, toutes ses variables locales sont supprimées.Cependant, si nous renvoyons la fonction interne et l'attribuons à une variable fnc pour qu'il persiste après outer a sorti, toutes les variables qui étaient dans la portée lorsque inner a été défini aussi persister.La variable a a été fermé -- il est en cours de fermeture.

Notez que la variable a est totalement privé pour fnc.Il s'agit d'une manière de créer des variables privées dans un langage de programmation fonctionnel tel que JavaScript.

Comme vous pourrez peut-être le deviner, quand j'appelle fnc() il imprime la valeur de a, qui vaut "1".

Dans un langage sans fermeture, la variable a aurait été collecté et jeté lorsque la fonction outer sorti.Appeler fnc aurait généré une erreur car a n'existe plus.

En JavaScript, la variable a persiste car la portée de la variable est créée lorsque la fonction est déclarée pour la première fois et persiste aussi longtemps que la fonction continue d'exister.

a appartient au champ d'application de outer.La portée de inner a un pointeur parent vers la portée de outer. fnc est une variable qui pointe vers inner. a persiste aussi longtemps que fnc persiste. a est dans la fermeture.

Autres conseils

Je vais donner un exemple (en JavaScript):

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}

var x = makeCounter();

x(); returns 1

x(); returns 2

...etc...

Ce que fait cette fonction, makeCounter, c'est qu'elle renvoie une fonction, que nous avons appelée x, qui comptera de un à chaque fois qu'elle sera appelée.Puisque nous ne fournissons aucun paramètre à x, il doit en quelque sorte se souvenir du décompte.Il sait où le trouver en fonction de ce qu'on appelle la portée lexicale : il doit rechercher l'endroit où il est défini pour trouver la valeur.Cette valeur « cachée » est ce qu’on appelle une fermeture.

Voici à nouveau mon exemple de curry :

function add (a) {
  return function (b) {
    return a + b;
  }
}

var add3 = add(3);

add3(4); returns 7

Ce que vous pouvez voir, c'est que lorsque vous appelez add avec le paramètre a (qui vaut 3), cette valeur est contenue dans la fermeture de la fonction renvoyée que nous définissons comme étant add3.De cette façon, lorsque nous appelons add3, il sait où trouver la valeur pour effectuer l'addition.

La réponse de Kyle c'est plutôt bien.Je pense que la seule précision supplémentaire est que la fermeture est essentiellement un instantané de la pile au moment où la fonction lambda est créée.Ensuite, lorsque la fonction est réexécutée, la pile est restaurée dans cet état avant d'exécuter la fonction.Ainsi, comme Kyle le mentionne, cette valeur cachée (count) est disponible lorsque la fonction lambda s'exécute.

Tout d'abord, contrairement à ce que la plupart des gens ici vous disent, la fermeture est pas une fonction!Et alors est il?
C'est un ensemble de symboles définis dans le « contexte environnant » d'une fonction (appelé son environnement) ce qui en fait une expression FERMÉE (c'est-à-dire une expression dans laquelle chaque symbole est défini et a une valeur, afin qu'il puisse être évalué).

Par exemple, lorsque vous disposez d'une fonction JavaScript :

function closed(x) {
  return x + 3;
}

c'est un expression fermée car tous les symboles qui y apparaissent y sont définis (leurs significations sont claires), vous pouvez donc l'évaluer.En d'autres termes, c'est autonome.

Mais si vous avez une fonction comme celle-ci :

function open(x) {
  return x*y + 3;
}

c'est un expression ouverte parce qu'il contient des symboles qui n'y ont pas été définis.À savoir, y.En regardant cette fonction, nous ne pouvons pas dire ce que y est et qu'est-ce que cela signifie, nous ne connaissons pas sa valeur, nous ne pouvons donc pas évaluer cette expression.C'est à dire.nous ne pouvons pas appeler cette fonction tant que nous n'avons pas dit quoi y est censé signifier là-dedans.Ce y s'appelle un variable libre.

Ce y demande une définition, mais cette définition ne fait pas partie de la fonction – elle est définie ailleurs, dans son « contexte environnant » (également connu sous le nom de environnement).C'est du moins ce que nous espérons :P

Par exemple, cela pourrait être défini globalement :

var y = 7;

function open(x) {
  return x*y + 3;
}

Ou il pourrait être défini dans une fonction qui l'enveloppe :

var global = 2;

function wrapper(y) {
   var w = "unused";

   return function(x) {
     return x*y + 3;
   }

}

La partie de l'environnement qui donne leur signification aux variables libres dans une expression est la fermeture.On l'appelle ainsi parce qu'il transforme un ouvrir expression dans un fermé premièrement, en fournissant ces définitions manquantes pour l'ensemble de ses variables libres, afin que nous puissions l'évaluer.

Dans l'exemple ci-dessus, la fonction interne (à laquelle nous n'avons pas donné de nom car nous n'en avions pas besoin) est un expression ouverte parce que la variable y dedans c'est gratuit – sa définition est en dehors de la fonction, dans la fonction qui l'enveloppe.Le environnement pour cette fonction anonyme est l'ensemble des variables :

{
  global: 2,
  w: "unused",
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

Maintenant le fermeture est-ce une partie de cet environnement qui se ferme la fonction interne en fournissant les définitions de tous ses variables libres.Dans notre cas, la seule variable libre dans la fonction interne était y, donc la fermeture de cette fonction est ce sous-ensemble de son environnement :

{
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

Les deux autres symboles définis dans l'environnement sont pas partie de la fermeture de cette fonction, car elle ne nécessite pas leur exécution.Ils ne sont pas nécessaires pour fermer il.

En savoir plus sur la théorie derrière cela ici :https://stackoverflow.com/a/36878651/434562

Il convient de noter que dans l'exemple ci-dessus, la fonction wrapper renvoie sa fonction interne sous forme de valeur.Le moment où nous appelons cette fonction peut être éloigné dans le temps du moment où la fonction a été définie (ou créée).En particulier, sa fonction d'encapsulation n'est plus en cours d'exécution, et ses paramètres qui étaient sur la pile d'appels ne sont plus là :P Cela pose problème, car la fonction interne a besoin y être là quand on l'appelle !En d'autres termes, il faut que les variables de sa fermeture soient d'une manière ou d'une autre survivre à la fonction wrapper et être là en cas de besoin.Par conséquent, la fonction interne doit faire un instantané de ces variables qui effectuent sa fermeture et les stockent dans un endroit sûr pour une utilisation ultérieure.(Quelque part en dehors de la pile d'appels.)

Et c'est pourquoi les gens confondent souvent le terme fermeture être ce type spécial de fonction qui peut créer de tels instantanés des variables externes qu'elles utilisent, ou de la structure de données utilisée pour stocker ces variables pour plus tard.Mais j'espère que tu comprends maintenant qu'ils le sont pas la fermeture elle-même – ce ne sont que des moyens de mettre en œuvre des fermetures dans un langage de programmation, ou des mécanismes de langage qui permettent aux variables de la fermeture de la fonction d'être là en cas de besoin.Il existe de nombreuses idées fausses autour des fermetures qui rendent (inutilement) ce sujet beaucoup plus confus et compliqué qu'il ne l'est en réalité.

Une fermeture est une fonction qui peut référencer un état dans une autre fonction.Par exemple, en Python, cela utilise la fermeture « inner » :

def outer (a):
    b = "variable in outer()"
    def inner (c):
        print a, b, c
    return inner

# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1

Pour faciliter la compréhension des fermetures, il pourrait être utile d'examiner comment elles pourraient être mises en œuvre dans un langage procédural.Cette explication fera suite à une implémentation simpliste des fermetures dans Scheme.

Pour commencer, je dois introduire le concept d'espace de noms.Lorsque vous entrez une commande dans un interpréteur Scheme, celui-ci doit évaluer les différents symboles de l'expression et obtenir leur valeur.Exemple:

(define x 3)

(define y 4)

(+ x y) returns 7

Les expressions de définition stockent la valeur 3 au point pour x et la valeur 4 au point pour y.Ensuite, lorsque nous appelons (+ x y), l'interpréteur recherche les valeurs dans l'espace de noms et est capable d'effectuer l'opération et de renvoyer 7.

Cependant, dans Scheme, il existe des expressions qui vous permettent de remplacer temporairement la valeur d'un symbole.Voici un exemple :

(define x 3)

(define y 4)

(let ((x 5))
   (+ x y)) returns 9

x returns 3

Le mot clé let introduit un nouvel espace de noms avec x comme valeur 5.Vous remarquerez qu'il est toujours capable de voir que y vaut 4, ce qui fait que la somme renvoyée est 9.Vous pouvez également voir qu’une fois l’expression terminée, x redevient 3.En ce sens, x a été temporairement masqué par la valeur locale.

Les langages procéduraux et orientés objet ont un concept similaire.Chaque fois que vous déclarez une variable dans une fonction qui porte le même nom qu'une variable globale, vous obtenez le même effet.

Comment pourrions-nous mettre cela en œuvre ?Un moyen simple consiste à utiliser une liste chaînée : la tête contient la nouvelle valeur et la queue contient l'ancien espace de noms.Lorsque vous avez besoin de rechercher un symbole, vous commencez par la tête et descendez vers la queue.

Passons maintenant à l'implémentation de fonctions de première classe pour le moment.Plus ou moins, une fonction est un ensemble d'instructions à exécuter lorsque la fonction est appelée et aboutissant à la valeur de retour.Lorsque nous lisons une fonction, nous pouvons stocker ces instructions en arrière-plan et les exécuter lorsque la fonction est appelée.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns ?

Nous définissons x comme étant 3 et plus-x comme étant son paramètre, y, plus la valeur de x.Enfin on appelle plus-x dans un environnement où x a été masqué par un nouveau x, celui-ci valant 5.Si nous stockons simplement l'opération (+ x y) pour la fonction plus-x, puisque nous sommes dans le contexte où x vaut 5, le résultat renvoyé serait 9.C'est ce qu'on appelle la portée dynamique.

Cependant, Scheme, Common Lisp et de nombreux autres langages ont ce qu'on appelle la portée lexicale : en plus de stocker l'opération (+ x y), nous stockons également l'espace de noms à ce stade particulier.De cette façon, lorsque nous recherchons les valeurs, nous pouvons voir que x, dans ce contexte, vaut réellement 3.C'est une fermeture.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns 7

En résumé, nous pouvons utiliser une liste chaînée pour stocker l'état de l'espace de noms au moment de la définition de la fonction, nous permettant d'accéder aux variables à partir des portées englobantes, ainsi que la possibilité de masquer localement une variable sans affecter le reste de l'espace de noms. programme.

Voici un exemple concret de la raison pour laquelle les fermetures sont un véritable casse-tête...Ceci vient directement de mon code Javascript.Permettez-moi d'illustrer.

Function.prototype.delay = function(ms /*[, arg...]*/) {
  var fn = this,
      args = Array.prototype.slice.call(arguments, 1);

  return window.setTimeout(function() {
      return fn.apply(fn, args);
  }, ms);
};

Et voici comment vous l'utiliseriez :

var startPlayback = function(track) {
  Player.play(track);  
};
startPlayback(someTrack);

Imaginez maintenant que vous souhaitiez que la lecture démarre retardée, comme par exemple 5 secondes plus tard après l'exécution de cet extrait de code.Eh bien, c'est facile avec delay et c'est la fermeture :

startPlayback.delay(5000, someTrack);
// Keep going, do other things

Quand vous appelez delay avec 5000ms, le premier extrait s'exécute et stocke les arguments transmis dans sa fermeture.Puis 5 secondes plus tard, lorsque le setTimeout le rappel se produit, la fermeture conserve toujours ces variables, elle peut donc appeler la fonction d'origine avec les paramètres d'origine.
Il s'agit d'un type de curry ou de décoration de fonction.

Sans fermetures, vous devrez d'une manière ou d'une autre maintenir l'état de ces variables en dehors de la fonction, jonchant ainsi le code en dehors de la fonction avec quelque chose qui lui appartient logiquement.L'utilisation de fermetures peut grandement améliorer la qualité et la lisibilité de votre code.

tl;dr

Une fermeture est une fonction et sa portée attribuée à (ou utilisée comme) une variable.Ainsi, la fermeture du nom :la portée et la fonction sont entourées et utilisées comme n'importe quelle autre entité.

Explication détaillée de style Wikipédia

Selon Wikipédia, une fermeture est:

Techniques d'implémentation de la liaison de noms à portée lexicale dans des langages dotés de fonctions de première classe.

Qu'est-ce que cela signifie?Examinons quelques définitions.

J'expliquerai les fermetures et autres définitions associées en utilisant cet exemple :

function startAt(x) {
    return function (y) {
        return x + y;
    }
}

var closure1 = startAt(1);
var closure2 = startAt(5);

console.log(closure1(3)); // 4 (x == 1, y == 3)
console.log(closure2(3)); // 8 (x == 5, y == 3)

Fonctions de première classe

En gros, cela signifie nous pouvons utiliser des fonctions comme n'importe quelle autre entité.Nous pouvons les modifier, les passer comme arguments, les renvoyer depuis des fonctions ou les affecter à des variables.Techniquement parlant, ils sont des citoyens de première classe, d'où le nom:fonctions de première classe.

Dans l'exemple ci-dessus, startAt renvoie un (anonyme) fonction à laquelle la fonction est affectée closure1 et closure2.Ainsi, comme vous le voyez, JavaScript traite les fonctions comme n'importe quelle autre entité (citoyens de première classe).

Liaison de nom

Liaison de nom il s'agit de découvrir quelles données une variable (identifiant) les références.La portée est vraiment importante ici, car c'est ce qui déterminera la manière dont une liaison est résolue.

Dans l'exemple ci-dessus :

  • Dans le cadre de la fonction anonyme interne, y est lié à 3.
  • Dans startAtla portée, x est lié à 1 ou 5 (en fonction de la fermeture).

Dans la portée de la fonction anonyme, x n'est lié à aucune valeur, il doit donc être résolu dans une valeur supérieure (startAt's) portée.

Cadrage lexical

Comme Wikipédia dit, Le viseur:

Est la région d'un programme informatique où la liaison est valide : où le nom peut être utilisé pour faire référence à l'entité.

Il existe deux techniques :

  • Portée lexicale (statique) :La définition d'une variable est résolue en recherchant son bloc ou sa fonction conteneur, puis si cela échoue, en recherchant le bloc conteneur externe, et ainsi de suite.
  • Cadrage dynamique :La fonction appelante est recherchée, puis la fonction qui a appelé cette fonction appelante, et ainsi de suite, en progressant dans la pile d'appels.

Pour plus d'explications, regarde cette question et jetez un oeil à Wikipédia.

Dans l'exemple ci-dessus, nous pouvons voir que JavaScript a une portée lexicale, car lorsque x est résolu, la liaison est recherchée dans la partie supérieure (startAt's), basée sur le code source (la fonction anonyme qui recherche x est définie à l'intérieur startAt) et non basé sur la pile d'appels, la manière (la portée où) la fonction a été appelée.

Conclusion (clôture)

Dans notre exemple, lorsque nous appelons startAt, il renverra une fonction (de première classe) qui sera attribuée à closure1 et closure2 ainsi une fermeture est créée, car les variables passées 1 et 5 sera enregistré dans startAtLa portée de , qui sera jointe à la fonction anonyme renvoyée.Lorsque nous appelons cette fonction anonyme via closure1 et closure2 avec le même argument (3), la valeur de y sera trouvé immédiatement (car c'est le paramètre de cette fonction), mais x n'est pas lié à la portée de la fonction anonyme, donc la résolution continue dans la portée de la fonction supérieure (lexiquement) (qui a été enregistrée lors de la fermeture) où x se révèle lié soit à 1 ou 5.Nous savons maintenant tout pour la sommation afin que le résultat puisse être renvoyé, puis imprimé.

Vous devez maintenant comprendre les fermetures et leur comportement, ce qui est un élément fondamental de JavaScript.

Curry

Oh, et tu as aussi appris quoi curry est à propos:vous utilisez des fonctions (fermetures) pour transmettre chaque argument d'une opération au lieu d'utiliser une fonction avec plusieurs paramètres.

Les fonctions ne contenant aucune variable libre sont appelées fonctions pures.

Les fonctions contenant une ou plusieurs variables libres sont appelées fermetures.

var pure = function pure(x){
  return x 
  // only own environment is used
}

var foo = "bar"

var closure = function closure(){
  return foo 
  // foo is a free variable from the outer environment
}

src : https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-impure

Dans une situation normale, les variables sont liées par une règle de portée :Les variables locales fonctionnent uniquement dans la fonction définie.La fermeture est un moyen d’enfreindre temporairement cette règle par commodité.

def n_times(a_thing)
  return lambda{|n| a_thing * n}
end

dans le code ci-dessus, lambda(|n| a_thing * n} c'est la fermeture parce que a_thing est référencé par le lambda (un créateur de fonction anonyme).

Maintenant, si vous placez la fonction anonyme résultante dans une variable de fonction.

foo = n_times(4)

foo enfreindra la règle de portée normale et commencera à utiliser 4 en interne.

foo.call(3)

renvoie 12.

En bref, le pointeur de fonction n'est qu'un pointeur vers un emplacement dans la base de code du programme (comme le compteur de programme).Alors que Fermeture = Pointeur de fonction + Cadre de pile.

.

Fermeture est une fonctionnalité de JavaScript où une fonction a accès à ses propres variables de portée, accès aux variables de fonction externes et accès aux variables globales.

La fermeture a accès à la portée de sa fonction externe même après le retour de la fonction externe.Cela signifie qu'une fermeture peut mémoriser et accéder aux variables et arguments de sa fonction externe même une fois la fonction terminée.

La fonction interne peut accéder aux variables définies dans sa propre portée, la portée de la fonction externe et la portée globale.Et la fonction externe peut accéder à la variable définie dans sa propre portée et dans la portée globale.

******************
Example of Closure
******************

var globalValue = 5;

function functOuter() 
{
    var outerFunctionValue = 10;

    //Inner function has access to the outer function value
    //and the global variables
    function functInner() 
    {
        var innerFunctionValue = 5;
        alert(globalValue+outerFunctionValue + innerFunctionValue);
    }
    functInner();
}
functOuter();

La sortie sera de 20, somme de sa propre variable de fonction interne, de sa variable de fonction externe et de la valeur de sa variable globale.

Voici un autre exemple réel utilisant un langage de script populaire dans les jeux - Lua.J'avais besoin de modifier légèrement le fonctionnement d'une fonction de bibliothèque pour éviter un problème avec stdin non disponible.

local old_dofile = dofile

function dofile( filename )
  if filename == nil then
    error( 'Can not use default of stdin.' )
  end

  old_dofile( filename )
end

La valeur de old_dofile disparaît lorsque ce bloc de code termine sa portée (car il est local), mais la valeur a été entourée d'une fermeture, donc la nouvelle fonction dofile redéfinie PEUT y accéder, ou plutôt une copie stockée avec la fonction en tant que fichier. « valorisation ».

Depuis Lua.org:

Lorsqu'une fonction est écrite incluse dans une autre fonction, elle a un accès complet aux variables locales de la fonction englobante ;cette fonctionnalité est appelée portée lexicale.Même si cela peut paraître évident, ce n’est pas le cas.La portée lexicale, associée à des fonctions de première classe, est un concept puissant dans un langage de programmation, mais peu de langages prennent en charge ce concept.

Si vous êtes issu du monde Java, vous pouvez comparer une fermeture avec une fonction membre d'une classe.Regardez cet exemple

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

La fonction g est une fermeture : g se ferme a dans.Donc g peut être comparé à une fonction membre, a peut être comparé à un champ de classe, et la fonction f avec une classe.

Fermetures chaque fois que nous avons une fonction définie dans une autre fonction, la fonction interne a accès aux variables déclarées dans la fonction extérieure.Les fermetures sont mieux expliquées avec des exemples.Dans Listing 2-18, vous pouvez voir que la fonction intérieure a accès à une variable (variableInouterFunction) à partir de la portée extérieure.Les variables de la fonction externe ont été fermées par (ou liées) à la fonction interne.D'où le terme fermeture.Le concept en lui-même est assez simple et assez intuitif.

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;

     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

source: http://index-of.es/Varios/Basarat%20Ali%20Syed%20(auth.)-Beginning%20Node.js-Apress%20(2014).pdf

Veuillez consulter le code ci-dessous pour comprendre la fermeture plus en profondeur :

        for(var i=0; i< 5; i++){            
            setTimeout(function(){
                console.log(i);
            }, 1000);                        
        }

Ici, quel sera le résultat ? 0,1,2,3,4 ce ne sera pas le cas 5,5,5,5,5 à cause de la fermeture

Alors, comment cela va-t-il résoudre ?La réponse est ci-dessous :

       for(var i=0; i< 5; i++){
           (function(j){     //using IIFE           
                setTimeout(function(){
                               console.log(j);
                           },1000);
            })(i);          
        }

Laissez-moi vous expliquer simplement, lorsqu'une fonction créée, rien ne se passe jusqu'à ce qu'elle appelle la boucle for dans le 1er code appelé 5 fois mais pas appelée immédiatement, donc quand elle a appelé, c'est-à-dire après 1 seconde et c'est également asynchrone donc avant que cette boucle for ne soit terminée et stocke la valeur 5 dans var i et enfin exécuter setTimeout fonction cinq fois et impression 5,5,5,5,5

Voici comment cela se résout en utilisant IIFE, c'est-à-dire l'expression de fonction d'invocation immédiate

       (function(j){  //i is passed here           
            setTimeout(function(){
                           console.log(j);
                       },1000);
        })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

Pour en savoir plus, veuillez comprendre le contexte d'exécution pour comprendre la fermeture.

  • Il existe une autre solution pour résoudre ce problème en utilisant let (fonctionnalité ES6), mais sous le capot, la fonction ci-dessus fonctionne

     for(let i=0; i< 5; i++){           
         setTimeout(function(){
                        console.log(i);
                    },1000);                        
     }
    
    Output: 0,1,2,3,4
    

=> Plus d'explications :

En mémoire, lorsque la boucle for exécute l'image, faites comme ci-dessous :

Boucle 1)

     setTimeout(function(){
                    console.log(i);
                },1000);  

Boucle 2)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Boucle 3)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Boucle 4)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Boucle 5)

     setTimeout(function(){
                    console.log(i);
                },1000);  

Ici, je ne suis pas exécuté, puis après une boucle complète, var j'ai stocké la valeur 5 en mémoire mais sa portée est toujours visible dans sa fonction enfant, donc lorsque la fonction s'exécute à l'intérieur setTimeout il s'imprime cinq fois 5,5,5,5,5

donc pour résoudre ce problème, utilisez IIFE comme expliqué ci-dessus.

Curry :Il vous permet d'évaluer partiellement une fonction en transmettant uniquement un sous-ensemble de ses arguments.Considère ceci:

function multiply (x, y) {
  return x * y;
}

const double = multiply.bind(null, 2);

const eight = double(4);

eight == 8;

Fermeture:Une fermeture n'est rien de plus que l'accès à une variable en dehors de la portée d'une fonction.Il est important de se rappeler qu'une fonction à l'intérieur d'une fonction ou une fonction imbriquée n'est pas une fermeture.Les fermetures sont toujours utilisées lorsqu'il est nécessaire d'accéder aux variables en dehors de la portée de la fonction.

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}

apple(3);

// the answer here will be 21

La fermeture est très simple.Nous pouvons le considérer comme suit :Fermeture = fonction + son environnement lexical

Considérons la fonction suivante :

function init() {
    var name = “Mozilla”;
}

Quelle sera la fermeture dans le cas ci-dessus ?Fonction init() et variables dans son environnement lexical, c'est-à-dire le nom.Fermeture = init() + nom

Considérons une autre fonction :

function init() {
    var name = “Mozilla”;
    function displayName(){
        alert(name);
}
displayName();
}

Quelles seront les fermetures ici ?La fonction interne peut accéder aux variables de la fonction externe.displayName() peut accéder au nom de variable déclaré dans la fonction parent, init().Cependant, les mêmes variables locales dans displayName() seront utilisées si elles existent.

Fermeture 1 : fonction init + (nom variable + fonction displayName()) --> portée lexicale

Fermeture 2 : Fonction displayName + (variable de nom) --> portée lexicale

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top