34 votes

Une confusion de fermeture JavaScript

→ jsFiddle

function f1(){
    var n=999;

    nAdd=function(){n+=1;};

    function f2(){
        alert(n);
    }
    return f2;
}

var result = f1();
var result2 = f1();

result();  // 999
nAdd();
result2(); // 1000
result2(); // 1000
result();  // 999

J'essaie d'apprendre les fermetures JavaScript, mais le code ci-dessus me laisse perplexe. Lorsque la première fois result() s'appelle, c'est 999. C'est bon pour moi.

Après nAdd() s'appelle, result2() affiche 1000. Et je pense que cela est dû à la fonction result2() et la fonction result() sont égales à la fonction f1() .

Mais pourquoi le dernier result() afficher 999 au lieu de 1000 ?

36voto

nnnnnn Points 70578

Chaque fois f1() est appelé et crée une nouvelle fermeture avec sa propre structure locale. n variable.

Cependant, le nAdd est globale, et est donc écrasée chaque fois que la variable f1() est appelé - ce qui signifie appeler nAdd() ne fera qu'ajouter à la n dans le dernier fermeture.

MISE À JOUR : Si vous voulez pouvoir incrémenter les valeurs de n dans chaque fermeture indépendamment, vous pourriez faire quelque chose comme ceci :

function f1(){
    var n=999;
    return {
        incrementN : function(){n+=1;},
        getN : function f2(){console.log(n);}
    }
}    
var result = f1();
var result2 = f1();
result.getN(); // 999
result.incrementN();
result2.getN();//999
result2.incrementN();
result2.getN();//1000
result.getN();//1000

C'est-à-dire, avoir f1() retourne un objet contenant deux méthodes qui ne sont pas déclarées comme globales, et qui opèrent toutes deux sur la variable locale n de la fermeture à laquelle ils appartiennent.

27voto

Ken Kin Points 1604

Il y a déjà de bonnes réponses, mais je pense qu'une image serait utile pour comprendre.

enter image description here

13voto

Quentin Points 325526

Chaque fois que vous appelez f1() vous :

  • Créez une nouvelle variable (locale) appelée n avec une valeur de 999
  • Créer une nouvelle fonction sans nom affectée à la mondial nAdd qui modifie que n (et écrase toute fonction précédente assignée à nAdd )
  • Créez une nouvelle fonction que vous retournez et qui alerte la valeur de cette fonction. n

Vous appelez f1() deux fois, donc vous faites tout ça deux fois. La deuxième fois que vous l'appelez, vous écrasez nAdd avec une nouvelle fonction qui modifie le segundo n .

Cela vous laisse avec :

  • result() qui alerte le primero n
  • result2() qui alerte le segundo n
  • nAdd() qui incrémente le segundo n

result() sur la dernière ligne d'alertes 999 car il alerte la valeur de la primero n (qui n'a jamais été incrémenté).

4voto

Holger Points 13789

result y result2 contiennent le résultat de différentes invocations de f1 et contiennent donc différentes instances de la variable locale n . Chaque invocation d'une fonction peut avoir des valeurs différentes pour les variables locales de cette fonction. Cela s'applique même lorsqu'aucune fermeture n'est impliquée.

1voto

Secator Points 9827

El nAdd=function(){n+=1;}; crée une fonction globale qui est une fermeture à l'intérieur de f1() . Une fermeture a accès à toutes les variables de la portée de la fonction qui l'a créée. Ainsi, chaque fois que vous appelez f1() il crée un nouveau nAdd() qui a n valeur liée à la valeur de var n de l'appel de f1() .

Dans votre code ;

var result = f1();
var result2 = f1();
result(); // 999
nAdd();         // Created by "var result2 = f1();" and has the same 'n' value as function in result2
result2();//1000
result2();//1000
result();//999

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X