function closure - Comment fonctionnent les fermetures de JavaScript?




js programmation (25)

Comment expliqueriez-vous les fermetures JavaScript à une personne connaissant les concepts qui la composent (par exemple, les fonctions, les variables, etc.) sans comprendre les fermetures elles-mêmes?

J'ai vu l'exemple de Scheme donné sur Wikipedia, mais malheureusement cela n'a pas aidé.


Answers

Chaque fois que vous voyez le mot-clé de fonction dans une autre fonction, la fonction interne a accès aux variables de la fonction externe.

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

Cela consignera toujours 16, car bar peut accéder au x défini comme argument de foo et à tmp de foo .

C'est une fermeture. Une fonction n'a pas à retourner pour s'appeler une fermeture. Accéder simplement à des variables en dehors de votre portée lexicale immédiate crée une fermeture .

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

La fonction ci-dessus consignera également le journal 16, car bar peut toujours se référer à x et à tmp , même s’il ne se trouve plus directement dans la portée.

Cependant, étant donné que tmp traîne toujours à l'intérieur de la fermeture du bar , il est également incrémenté. Il sera incrémenté chaque fois que vous appelez bar .

L'exemple le plus simple d'une fermeture est le suivant:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

Lorsqu'une fonction JavaScript est appelée, un nouveau contexte d'exécution est créé. Avec les arguments de la fonction et l'objet parent, ce contexte d'exécution reçoit également toutes les variables déclarées en dehors de celui-ci (dans l'exemple ci-dessus, les deux expressions "a" et "b").

Il est possible de créer plusieurs fonctions de fermeture, soit en renvoyant une liste de celles-ci, soit en les définissant comme variables globales. Tous feront référence au même x et au même tmp , ils ne font pas leurs propres copies.

Ici, le nombre x est un nombre littéral. Comme avec les autres littéraux en JavaScript, lorsque foo est appelé, le nombre x est copié dans foo tant qu'argument x .

D'autre part, JavaScript utilise toujours des références lorsqu'il traite des objets. Si par exemple, vous avez appelé foo avec un objet, la fermeture qu'il renvoie fera référence à cet objet d'origine!

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

Comme prévu, chaque appel à la bar(10) incrémentera x.memb . Ce qui pourrait ne pas être attendu, c'est que x fait simplement référence au même objet que la variable age ! Après quelques appels au bar , age.memb sera 2! Ce référencement constitue la base des fuites de mémoire avec les objets HTML.


Une fonction en JavaScript n’est pas simplement une référence à un ensemble d’instructions (comme en langage C), elle inclut également une structure de données masquée composée de références à toutes les variables non locales qu’elle utilise (variables capturées). Ces fonctions en deux parties sont appelées fermetures. Chaque fonction en JavaScript peut être considérée comme une fermeture.

Les fermetures sont des fonctions avec un état. C'est un peu similaire à "this" dans le sens où "this" fournit également un état pour une fonction mais function et "this" sont des objets séparés ("this" n'est qu'un paramètre de fantaisie, et le seul moyen de le lier de manière permanente à la fonction est de créer une fermeture). Bien que "this" et la fonction vivent toujours séparément, une fonction ne peut pas être séparée de sa fermeture et le langage ne fournit aucun moyen d'accéder aux variables capturées.

Toutes ces variables externes référencées par une fonction lexicalement imbriquée sont en fait des variables locales dans la chaîne de ses fonctions englobant lexicalement (les variables globales peuvent être supposées être des variables locales d'une fonction racine), et chaque exécution d'une fonction crée de nouvelles instances de Il en résulte que chaque exécution d’une fonction renvoyant (ou transférant d’une autre manière, par exemple son enregistrement en tant que callback) une fonction imbriquée crée une nouvelle fermeture (avec son propre ensemble potentiellement unique de variables non locales référencées qui représente son exécution. le contexte).

De plus, il faut bien comprendre que les variables locales en JavaScript ne sont pas créées sur le cadre de la pile, mais sur le tas, et ne sont détruites que lorsque personne ne les référence. Quand une fonction est retournée, les références à ses variables locales sont décrémentées, mais elles peuvent rester non nul si, au cours de l'exécution en cours, elles font partie d'une fermeture et sont toujours référencées par ses fonctions imbriquées lexiquement ces fonctions imbriquées ont été retournées ou autrement transférées à un code externe).

Un exemple:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();

Les enfants se souviendront toujours des secrets qu’ils ont partagés avec leurs parents, même après le départ de leurs parents. C'est ce que les fermetures sont pour les fonctions.

Les secrets pour les fonctions JavaScript sont les variables privées

var parent = function() {
 var name = "Mary"; // secret
}

Chaque fois que vous l'appelez, la variable locale "nom" est créée et appelée "Marie". Et chaque fois que la fonction quitte la variable est perdue et le nom est oublié.

Comme vous pouvez le deviner, étant donné que les variables sont recréées chaque fois que la fonction est appelée et que personne d'autre ne les connaît, il doit exister un endroit secret où elles sont stockées. Cela pourrait s'appeler la chambre des secrets ou pile ou portée locale, mais ce n'est pas grave. Nous savons qu'ils sont là, quelque part, cachés dans la mémoire.

Mais, dans JavaScript, il y a cette chose très spéciale que les fonctions qui sont créées dans d'autres fonctions peuvent également connaître les variables locales de leurs parents et les conserver aussi longtemps qu'elles vivent.

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

Donc, tant que nous sommes dans la fonction parent, il peut créer une ou plusieurs fonctions enfants qui partagent les variables secrètes à partir de l'endroit secret.

Mais ce qui est triste, c’est que si l’enfant est également une variable privée de sa fonction parent, il mourrait également lorsque le parent prend fin et les secrets mourraient avec eux.

Donc, pour vivre, l'enfant doit partir avant qu'il ne soit trop tard

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

Et maintenant, même si Mary "ne court plus", son souvenir n'est pas perdu et son enfant se souviendra toujours de son nom et des autres secrets qu'ils ont partagés au cours de leur vie commune.

Donc, si vous appelez l'enfant "Alice", elle répondra

child("Alice") => "My name is Alice, child of Mary"

C'est tout ce qu'il y a à dire.


J'ai tendance à apprendre mieux par des comparaisons BON / BAD. J'aime voir le code de travail suivi du code de non-travail que quelqu'un est susceptible de rencontrer J'ai assemblé un jsFiddle qui fait une comparaison et essaie de résumer les différences aux explications les plus simples que je pourrais trouver.

Fermetures bien faites:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index in arr) {
    console.log(arr[index]());
}
  • Dans ce qui précède, le code createClosure(n)est invoqué à chaque itération de la boucle. Notez que j'ai nommé la variable npour souligner qu'il s'agit d'une nouvelle variable créée dans une nouvelle portée de fonction et n'est pas la même que indexcelle liée à la portée externe.

  • Cela crée une nouvelle portée et nest lié à cette portée; Cela signifie que nous avons 10 portées distinctes, une pour chaque itération.

  • createClosure(n) renvoie une fonction qui renvoie le n dans cette étendue.

  • Chaque portée nest liée à la valeur qu'elle avait lors de l' createClosure(n)appel, de sorte que la fonction imbriquée renvoyée renvoie toujours la valeur de ncelle qu'elle avait lors de l' createClosure(n)appel.

Fermetures mal faites:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index in badArr) {
    console.log(badArr[index]());
}
  • Dans le code ci-dessus, la boucle a été déplacée dans la createClosureArray()fonction et celle-ci ne fait que renvoyer le tableau complet, ce qui, à première vue, semble plus intuitif.

  • Ce qui n’est peut-être pas évident, c’est que puisque createClosureArray()n’est appelé qu’une fois, une seule portée est créée pour cette fonction au lieu d’une pour chaque itération de la boucle.

  • Dans cette fonction, une variable nommée indexest définie. La boucle s'exécute et ajoute des fonctions au tableau renvoyé index. Notez que cela indexest défini dans la createClosureArrayfonction qui n'est appelée qu'une seule fois.

  • Comme il n'y avait qu'une seule étendue dans la createClosureArray()fonction, elle indexn'est liée qu'à une valeur à l'intérieur de cette étendue. En d'autres termes, chaque fois que la boucle change la valeur de index, elle la modifie pour tout ce qui la référence dans cette étendue.

  • Toutes les fonctions ajoutées au tableau renvoient la indexvariable SAME de la portée parente où elle a été définie au lieu de 10 variables différentes parmi 10 étendues différentes, comme dans le premier exemple. Le résultat final est que toutes les 10 fonctions renvoient la même variable à partir de la même portée.

  • Une fois la boucle terminée et en indexcours de modification, la valeur finale était de 10; par conséquent, chaque fonction ajoutée au tableau renvoie la valeur de la indexvariable unique , qui est maintenant définie sur 10.

Résultat

FERMETURES FAITES À DROITE
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

FERMETURES fait de mal
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10


Une fermeture est l'endroit où une fonction interne a accès à des variables dans sa fonction externe. C'est probablement l'explication d'une ligne la plus simple que vous pouvez obtenir pour les fermetures.


Je les dirigerais simplement vers la page Mozilla Closures . C'est l' explication la plus concise et la plus simple et la plus concise et la plus simple des bases et de l'utilisation pratique de la fermeture que j'ai trouvée. Il est fortement recommandé à quiconque apprend le langage JavaScript.

Et oui, je le recommanderais même à un enfant de 6 ans - si l'enfant de 6 ans en apprend sur les fermetures, il est logique qu'il soit prêt à comprendre l' explication simple et concise fournie dans l'article.


Il s'agit d'une tentative pour dissiper plusieurs malentendus (possibles) sur les fermetures qui apparaissent dans certaines des autres réponses.

  • Une fermeture n'est pas créée uniquement lorsque vous retournez une fonction interne. En fait, la fonction englobante n'a pas besoin de revenir du tout pour que sa fermeture soit créée. Vous pouvez plutôt affecter votre fonction interne à une variable d'une étendue externe ou la transmettre en tant qu'argument à une autre fonction où elle pourrait être appelée immédiatement ou à tout moment ultérieurement. Par conséquent, la fermeture de la fonction englobante est probablement créée dès que la fonction englobante est appelée car toute fonction interne a accès à cette fermeture à chaque appel de la fonction interne, avant ou après le retour de la fonction englobante.
  • Une fermeture ne fait pas référence à une copie des anciennes valeurs des variables dans son étendue. Les variables elles-mêmes font partie de la clôture. La valeur affichée lors de l’accès à l’une de ces variables est donc la dernière valeur au moment de son accès. C'est pourquoi les fonctions internes créées dans des boucles peuvent être délicates, car chacune d'entre elles a accès aux mêmes variables externes au lieu de récupérer une copie des variables au moment où la fonction est créée ou appelée.
  • Les "variables" dans une fermeture incluent toutes les fonctions nommées déclarées dans la fonction. Ils incluent également des arguments de la fonction. Une fermeture a également accès aux variables de la fermeture qui la contient, jusqu'à la portée globale.
  • Les fermetures utilisent la mémoire, mais elles ne causent pas de fuites de mémoire, car JavaScript nettoie ses propres structures circulaires qui ne sont pas référencées. Des fuites de mémoire Internet Explorer impliquant des fermetures sont créées lorsqu'il ne parvient pas à déconnecter les valeurs d'attribut DOM faisant référence à des fermetures, conservant ainsi des références à des structures éventuellement circulaires.

OK, fan de fermetures de 6 ans. Voulez-vous entendre le plus simple exemple de fermeture?

Imaginons la situation suivante: un conducteur est assis dans une voiture. Cette voiture est dans un avion. L'avion est à l'aéroport. La possibilité pour le conducteur d'accéder à des objets extérieurs à sa voiture, mais à l'intérieur de l'avion, même si cet avion quitte un aéroport, constitue une fermeture. C'est tout.Quand vous aurez 27 ans, regardez l' explication plus détaillée ou l'exemple ci-dessous.

Voici comment je peux convertir mon histoire d'avion dans le code.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");


En tant que père d'un enfant de 6 ans, enseignant actuellement à de jeunes enfants (et novice relative au codage sans éducation formelle, des corrections seront nécessaires), je pense que la leçon serait meilleure par des jeux pratiques. Si l'enfant de 6 ans est prêt à comprendre ce qu'est une fermeture, il est alors assez vieux pour tenter sa chance. Je suggèrerais de coller le code dans jsfiddle.net, d’en expliquer un peu et de les laisser seuls pour concocter une chanson unique. Le texte explicatif ci-dessous est probablement plus approprié pour un enfant de 10 ans.

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

INSTRUCTIONS

DONNÉES: Les données sont un ensemble de faits. Cela peut être des chiffres, des mots, des mesures, des observations ou même simplement des descriptions de choses. Vous ne pouvez pas le toucher, le sentir ou le goûter. Vous pouvez l'écrire, le parler et l'entendre. Vous pouvez l'utiliser pour créer une odeur et un goût au toucher à l'aide d'un ordinateur. Cela peut être rendu utile par un ordinateur utilisant un code.

CODE: Toute l'écriture ci-dessus s'appelle du code . C'est écrit en JavaScript.

JAVASCRIPT: JavaScript est un langage. Comme l'anglais ou le français ou le chinois sont des langues. Il existe de nombreuses langues comprises par les ordinateurs et autres processeurs électroniques. Pour que JavaScript soit compris par un ordinateur, il nécessite un interprète. Imaginez si un enseignant qui ne parle que le russe vient enseigner votre classe à l'école. Lorsque l'enseignant dit "все садятся", la classe ne comprend pas. Mais heureusement, vous avez un élève russe dans votre classe qui dit à tout le monde que cela signifie "tout le monde s'assoit" - alors vous le faites tous. La classe est comme un ordinateur et l’élève russe est l’interprète. Pour JavaScript, l'interpréteur le plus courant s'appelle un navigateur.

NAVIGATEUR: lorsque vous vous connectez à Internet sur un ordinateur, une tablette ou un téléphone pour visiter un site Web, vous utilisez un navigateur. Des exemples que vous connaissez peut-être sont Internet Explorer, Chrome, Firefox et Safari. Le navigateur peut comprendre JavaScript et dire à l'ordinateur ce qu'il doit faire. Les instructions JavaScript sont appelées fonctions.

FONCTION: Une fonction en JavaScript est comme une usine. C'est peut-être une petite usine avec une seule machine à l'intérieur. Ou bien, il peut contenir de nombreuses autres petites usines, chacune avec de nombreuses machines effectuant différents travaux. Dans une vraie usine de vêtements, il se peut que des tonnes de tissu et des bobines de fil entrent et que des t-shirts et des jeans sortent. Notre usine JavaScript ne traite que des données, elle ne peut pas coudre, percer un trou ou faire fondre du métal. Dans notre usine JavaScript, les données entrent et sortent les données.

Toutes ces données semblent un peu ennuyeuses, mais c’est vraiment très cool; nous pourrions avoir une fonction qui dit à un robot quoi faire pour le dîner. Disons que je vous invite avec votre ami chez moi. Vous aimez le mieux les cuisses de poulet, j'aime les saucisses, votre ami veut toujours ce que vous voulez et mon ami ne mange pas de viande.

Je n'ai pas le temps d'aller faire les courses, alors la fonction doit savoir ce que nous avons dans le réfrigérateur pour prendre des décisions. Chaque ingrédient a un temps de cuisson différent et nous voulons que tout soit servi chaud par le robot en même temps. Nous devons fournir à la fonction des données sur ce que nous aimons, la fonction pourrait «parler» au réfrigérateur et la fonction pourrait contrôler le robot.

Une fonction a normalement un nom, des parenthèses et des accolades. Comme ça:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

Notez cela /*...*/et //arrêtez le code en cours de lecture par le navigateur.

NOM: Vous pouvez appeler une fonction à peu près n'importe quel mot. L'exemple "cookMeal" est typique en joignant deux mots et en donnant au second une lettre majuscule au début - mais ce n'est pas nécessaire. Il ne peut pas y avoir d'espace, ni de numéro.

PARENTHESES: Les "parenthèses" ou ()sont la boîte aux lettres située sur la porte de la fabrique de fonctions JavaScript ou une boîte aux lettres située dans la rue pour l'envoi de paquets d'informations à l'usine. Parfois, la boîte aux lettres peut être marquée, par exemple cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime) , auquel cas vous savez quelles données vous devez lui donner.

BRACES: Les "bretelles" qui ressemblent à ceci {}sont les vitres teintées de notre usine. De l'intérieur de l'usine, vous pouvez voir, mais de l'extérieur, vous ne pouvez pas voir dedans.

EXEMPLE DE LONG CODE CI-DESSUS

Notre code commence par le mot fonction , nous savons donc qu'il en est un! Ensuite, le nom de la fonction chante - c’est ma propre description de la fonction. Puis entre parenthèses () . Les parenthèses sont toujours là pour une fonction. Parfois , ils sont vides, et parfois ils ont quelque chose dans celui - ci a un mot.: (person). Après cela, il y a une attelle comme celle-ci {. Ceci marque le début de la fonction sing () . Il a un partenaire qui marque la fin de sing () comme ceci}

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

Donc, cette fonction peut avoir quelque chose à voir avec le chant et peut nécessiter des données sur une personne. Il contient des instructions pour faire quelque chose avec ces données.

Maintenant, après la fonction sing () , près de la fin du code se trouve la ligne

var person="an old lady";

VARIABLE: Les lettres var représentent "variable". Une variable est comme une enveloppe. À l'extérieur, cette enveloppe est marquée "personne". À l’intérieur, il contient un bout de papier reprenant les informations dont notre fonction a besoin, des lettres et des espaces réunis comme une ficelle (c’est une ficelle) qui forment une phrase disant "une vieille dame". Notre enveloppe peut contenir d'autres types d'éléments, tels que des nombres (appelés entiers), des instructions (appelées fonctions) et des listes (appelées tableaux ). Étant donné que cette variable est écrite en dehors de toutes les accolades {}et que vous pouvez voir à travers les fenêtres teintées lorsque vous êtes à l'intérieur des accolades, cette variable peut être vue de n'importe où dans le code. Nous appelons cela une "variable globale".

VARIABLE GLOBALE: personne est une variable globale, ce qui signifie que si vous changez sa valeur de "vieille dame" en "jeune homme", elle restera jeune jusqu'à ce que vous décidiez de la changer le code peut voir que c'est un jeune homme. Appuyez sur le F12bouton ou consultez les paramètres Options pour ouvrir la console de développement d'un navigateur et tapez "personne" pour connaître la valeur de cette valeur. Tapez person="a young man"pour le changer, puis tapez "personne" à nouveau pour voir qu'il a changé.

Après cela, nous avons la ligne

sing(person);

Cette ligne appelle la fonction, comme si elle appelait un chien

"Viens chanter , viens chercher quelqu'un !"

Lorsque le navigateur a chargé le code JavaScript et atteint cette ligne, il lance la fonction. Je mets la ligne à la fin pour m'assurer que le navigateur dispose de toutes les informations nécessaires à son exécution.

Les fonctions définissent les actions - la fonction principale est de chanter. Il contient une variable appelée firstPart qui s'applique au chant de la personne et qui s'applique à chacun des versets de la chanson: "Il y avait" + personne + "qui a avalé". Si vous tapez firstPart dans la console, vous n'obtiendrez pas de réponse car la variable est verrouillée dans une fonction - le navigateur ne peut pas voir à l'intérieur des fenêtres colorées des accolades.

FERMETURES: Les fermetures sont les plus petites fonctions qui se trouvent dans la grande fonction sing () . Les petites usines à l'intérieur de la grande usine. Ils ont chacun leur propre accolade, ce qui signifie que les variables qu’ils contiennent ne peuvent être vus de l’extérieur. C'est pourquoi les noms des variables ( créature et résultat ) peuvent être répétés dans les fermetures mais avec des valeurs différentes. Si vous tapez ces noms de variable dans la fenêtre de la console, vous n'obtiendrez pas sa valeur, car elle est masquée par deux couches de fenêtres teintées.

Les fermetures savent toutes ce qu'est la variable firstPart de la fonction sing () , car elles peuvent voir à partir de leurs fenêtres teintées.

Après les fermetures viennent les lignes

fly();
spider();
bird();
cat();

La fonction sing () appelle chacune de ces fonctions dans l'ordre dans lequel elles sont données. Ensuite, le travail de la fonction sing () sera terminé.


J'ai créé un didacticiel JavaScript interactif pour expliquer le fonctionnement des fermetures. Qu'est-ce qu'une fermeture?

Voici l'un des exemples:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here

D'accord, parlant avec un enfant de 6 ans, j'utiliserais probablement les associations suivantes.

Imaginez - vous jouez avec vos petits frères et soeurs dans toute la maison, et vous vous déplacez avec vos jouets et en emportez certains dans la chambre de votre grand frère. Après un moment, votre frère est rentré de l'école et est allé dans sa chambre. Il s'est enfermé à l'intérieur. Vous ne pouvez donc plus accéder directement aux jouets qui y sont restés. Mais vous pouvez frapper à la porte et demander à votre frère ces jouets. Ceci s'appelle la fermeture de toy ; votre frère fait pour vous, et il est maintenant en extérieur portée .

Comparez avec une situation où une porte a été verrouillée par un tirage et qu'il n'y a personne à l'intérieur (exécution générale des fonctions), puis un incendie local se produit et brûle la pièce (éboueur: D), puis une nouvelle pièce a été construite et vous pouvez maintenant quitter il y a un autre jouet (nouvelle instance de fonction), mais ne récupérez jamais les mêmes jouets qui ont été laissés dans la première instance.

Pour un enfant avancé, je mettrais quelque chose comme ceci. Ce n'est pas parfait, mais cela vous fait sentir ce que c'est:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

Comme vous pouvez le constater, les jouets laissés dans la pièce sont toujours accessibles via le frère, que la pièce soit ou non verrouillée. Voici un jsbin pour jouer avec.


J'ai écrit un article de blog il y a quelque temps expliquant les fermetures. Voici ce que j'ai dit à propos des fermetures en ce qui concerne les raisons pour lesquelles vous en voudriez une.

Les fermetures sont un moyen de laisser une fonction avoir des variables persistantes et privées , c'est-à-dire des variables que seule une fonction connaît, où elle peut garder une trace des informations de ses précédentes exécutions.

En ce sens, ils laissent une fonction agir un peu comme un objet avec des attributs privés.

Message complet:

Alors, quelles sont ces choses de fermeture?


Je ne comprends pas pourquoi les réponses sont si complexes ici.

Voici une fermeture:

var a = 42;

function b() { return a; }

Oui. Vous utilisez probablement cela plusieurs fois par jour.


Il n'y a aucune raison de croire que les fermetures sont un hack de conception complexe pour résoudre des problèmes spécifiques. Non, les fermetures consistent simplement à utiliser une variable qui provient d'une étendue supérieure du point de vue de l'endroit où la fonction a été déclarée (non exécutée) .

Maintenant, ce que cela vous permet de faire peut être plus spectaculaire, voir les autres réponses.


Les fermetures sont difficiles à expliquer car elles sont utilisées pour faire fonctionner un comportement que tout le monde s'attend intuitivement à travailler de toute façon. Je trouve la meilleure façon de les expliquer (et la façon dont j'ai appris ce qu'ils font) est d'imaginer la situation sans eux:

    var bind = function(x) {
        return function(y) { return x + y; };
    }
    
    var plus5 = bind(5);
    console.log(plus5(3));

Que se passerait-il ici si JavaScript ne connaissait pas les fermetures? Il suffit de remplacer l'appel de la dernière ligne par son corps de méthode (ce qui est fondamentalement le cas des appels de fonction) et vous obtenez:

console.log(x + 3);

Maintenant, où est la définition de x ? Nous ne l'avons pas défini dans la portée actuelle. La seule solution consiste à laisser plus5 transporter son périmètre (ou plutôt celui de son parent). De cette façon, x est bien défini et il est lié à la valeur 5.


Wikipedia sur les fermetures :

En informatique, une fermeture est une fonction associée à un environnement de référence pour les noms non locaux (variables libres) de cette fonction.

Techniquement, en JavaScript , chaque fonction est une fermeture . Il a toujours accès aux variables définies dans la portée environnante.

Etant donné que la construction définissant la portée en JavaScript est une fonction et non un bloc de code comme dans beaucoup d'autres langages, ce que nous entendons par fermeture en JavaScript est une fonction utilisant des variables non locales définies dans une fonction environnante déjà exécutée .

Les fermetures sont souvent utilisées pour créer des fonctions avec des données privées cachées (mais ce n'est pas toujours le cas).

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ems

L'exemple ci-dessus utilise une fonction anonyme, qui a été exécutée une fois. Mais ce n'est pas obligé. Il peut être nommé (par exemple mkdb) et exécuté ultérieurement, en générant une fonction de base de données chaque fois qu'il est appelé. Chaque fonction générée aura son propre objet de base de données caché. Un autre exemple d'utilisation de fermeture est le cas où nous ne renvoyons pas une fonction mais un objet contenant plusieurs fonctions à des fins différentes, chacune de ces fonctions ayant accès aux mêmes données.


Les fermetures sont simples:

L'exemple simple suivant couvre tous les points principaux des fermetures de JavaScript. *

Voici une usine qui produit des calculatrices qui peuvent ajouter et multiplier:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

Le point clé: chaque appel à make_calculatorcréer une nouvelle variable locale n, qui continue à être utilisable par la calculatrice addet multiplyfonctionne longtemps après le make_calculatorretour.

Si vous connaissez bien les cadres de pile, ces calculatrices semblent étranges: comment peuvent-elles continuer à accéder naprès les make_calculatorretours? La solution consiste à imaginer que JavaScript n'utilise pas de "cadres de pile", mais utilise des "cadres de tas", qui peuvent persister après l'appel de la fonction qui les a renvoyés.

Les fonctions internes comme addet multiply, qui accèdent aux variables déclarées dans une fonction externe ** , sont appelées fermetures .

C'est à peu près tout ce qu'il y a aux fermetures.


* Par exemple, il couvre tous les points de l'article "Fermetures pour les nuls" donné dans une autre réponse , à l'exception de l'exemple 6, qui montre simplement que des variables peuvent être utilisées avant d'être déclarées, ce qui est un fait intéressant à connaître mais totalement indépendant des fermetures. Il couvre également tous les points de la réponse acceptée , à l'exception des points (1) qui copient leurs arguments dans des variables locales (les arguments de la fonction nommée) et (2) qui copie des nombres crée un nouveau numéro, mais copie une référence d'objet. vous donne une autre référence au même objet. Celles-ci sont également utiles à connaître, mais là encore, elles n’ont aucun lien avec les fermetures. Il est également très similaire à l'exemple de cette réponse, mais un peu plus court et moins abstrait. Il ne couvre pas le point decette réponse ou ce commentaire , qui est que JavaScript rend difficile de brancher le courantvaleur d'une variable de boucle dans votre fonction interne: L'étape "brancher" ne peut être effectuée qu'avec une fonction d'assistance englobant votre fonction interne et appelée à chaque itération de la boucle. (À proprement parler, la fonction interne accède à la copie de la variable de la fonction d'assistance, plutôt que de rien brancher.) Encore une fois, très utile lors de la création de fermetures, mais ne faisant pas partie de ce qu'est une fermeture ou de son fonctionnement. Il existe une confusion supplémentaire en raison du fait que les fermetures fonctionnent différemment dans des langages fonctionnels tels que ML, où les variables sont liées à des valeurs plutôt qu’à l’espace de stockage, fournissant ainsi un flot constant de personnes qui comprennent les fermetures de manière tout simplement incorrect pour JavaScript, où les variables sont toujours liées à un espace de stockage et jamais à des valeurs.

** Toute fonction externe, si plusieurs sont imbriquées, ou même dans le contexte global, comme le montre clairement cette réponse .


Les fonctions JavaScript peuvent accéder à leurs:

  1. Arguments
  2. Locaux (c'est-à-dire leurs variables locales et leurs fonctions locales)
  3. Environnement, qui comprend:
    • globals, y compris le DOM
    • quoi que ce soit dans les fonctions externes

Si une fonction accède à son environnement, elle est une fermeture.

Notez que les fonctions externes ne sont pas nécessaires, bien qu'elles offrent des avantages dont je ne discute pas ici. En accédant aux données de son environnement, une fermeture maintient ces données en vie. Dans le sous-cas des fonctions externes / internes, une fonction externe peut créer des données locales et éventuellement sortir, et pourtant, si une ou plusieurs fonctions internes survivent après la sortie de la fonction externe, les fonctions internes conservent les données locales de la fonction externe vivant.

Exemple de fermeture utilisant l'environnement global:

Imaginez que les événements de bouton Vote-Up et Vote-Down de dépassement de pile soient implémentés en tant que fermetures, voteUp_click et voteDown_click, qui ont accès aux variables externes isVotedUp et isVotedDown, définies globalement. (Par souci de simplicité, je fais référence aux boutons Question Vote de , et non au tableau de boutons Réponse de vote.)

Lorsque l'utilisateur clique sur le bouton VoteUp, la fonction voteUp_click vérifie si isVotedDown == true pour déterminer s'il faut voter ou simplement annuler un vote négatif. La fonction voteUp_click est une fermeture car elle accède à son environnement.

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

Ces quatre fonctions sont des fermetures car elles accèdent toutes à leur environnement.


AVANT-PROPOS: cette réponse a été écrite alors que la question était:

Comme l'a dit le vieil Albert: "Si vous ne pouvez pas expliquer cela à un enfant de six ans, vous ne le comprenez vraiment pas vous-même.". J'ai essayé d'expliquer les fermetures de JS à un ami de 27 ans et j'ai complètement échoué.

Quelqu'un peut-il considérer que je suis 6 et étrangement intéressé par ce sujet?

Je suis à peu près sûr d'être l'une des seules personnes à avoir tenté de prendre la question initiale à la lettre. Depuis lors, la question a muté plusieurs fois, aussi ma réponse peut-elle maintenant sembler incroyablement stupide et déplacée. Espérons que l'idée générale de l'histoire reste amusante pour certains.

Je suis un grand fan d'analogie et de métaphore lorsque j'explique des concepts difficiles, alors laissez-moi m'essayer à une histoire.

Il était une fois:

Il y avait une princesse ...

function princess() {

Elle a vécu dans un monde merveilleux d'aventures. Elle a rencontré son prince charmant, parcouru son monde avec une licorne, combattant des dragons, rencontré des animaux qui parlent et de nombreuses autres choses fantastiques.

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

Mais elle devrait toujours retourner dans son monde monotone de tâches ménagères et d'adultes.

    return {

Et elle leur racontait souvent sa dernière aventure incroyable en tant que princesse.

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

Mais tout ce qu'ils verraient, c'est une petite fille ...

var littleGirl = princess();

... raconter des histoires de magie et de fantaisie.

littleGirl.story();

Et même si les adultes connaissaient de vraies princesses, ils ne croiraient jamais aux licornes ni aux dragons, car ils ne pourraient jamais les voir. Les grandes personnes ont dit qu'elles n'existaient que dans l'imaginaire de la petite fille.

Mais nous connaissons la vraie vérité. que la petite fille avec la princesse à l'intérieur ...

... est vraiment une princesse avec une petite fille à l'intérieur.


Une fermeture ressemble beaucoup à un objet. Il est instancié chaque fois que vous appelez une fonction.

L'étendue d'une fermeture en JavaScript est lexicale, ce qui signifie que tout ce qui est contenu dans la fonction à laquelle la fermeture appartient a accès à toutes les variables qu'il contient.

Une variable est contenue dans la fermeture si vous

  1. l'assigner avec var foo=1; ou
  2. Ecrivez var foo;

Si une fonction interne (une fonction contenue dans une autre fonction) accède à une telle variable sans la définir dans sa propre portée avec var, elle modifie le contenu de la variable dans la fermeture externe .

Une fermeture survit à l'exécution de la fonction qui l'a générée. Si d'autres fonctions sortent de la fermeture / de la portée dans laquelle elles sont définies (par exemple, en tant que valeurs de retour), elles continueront à référencer cette fermeture .

Exemple

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

Sortie

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

L'auteur de Closures a très bien expliqué les fermetures, en expliquant pourquoi nous en avons besoin et en expliquant LexicalEnvironment, qui est nécessaire à la compréhension des fermetures.
Voici le résumé:

Que se passe-t-il si une variable est accédée, mais qu'elle n'est pas locale? Comme ici:

Dans ce cas, l'interpréteur trouve la variable dans l' LexicalEnvironmentobjet externe .

Le processus comprend deux étapes:

  1. Tout d'abord, lorsqu'une fonction f est créée, elle n'est pas créée dans un espace vide. Il existe un objet LexicalEnvironment en cours. Dans le cas ci-dessus, il s'agit de la fenêtre (a n'est pas défini au moment de la création de la fonction).

Lorsqu'une fonction est créée, elle obtient une propriété cachée, nommée [[Scope]], qui fait référence au LexicalEnvironment actuel.

Si une variable est lue mais ne peut être trouvée nulle part, une erreur est générée.

Fonctions imbriquées

Les fonctions peuvent être imbriquées les unes dans les autres, formant une chaîne d’environnements Lexical pouvant également être appelée chaîne d’étendue.

Donc, la fonction g a accès à g, a et f.

Fermetures

Une fonction imbriquée peut continuer à vivre après la fin de la fonction externe:

Marquage des environnements lexicaux:

Comme nous le voyons, il this.says’agit d’une propriété dans l’objet utilisateur qui continue à vivre après la fin de l’utilisateur.

Et si vous vous en souvenez, lorsqu’elle this.sayest créée, elle (comme chaque fonction) obtient une référence interne this.say.[[Scope]]au LexicalEnvironment actuel. Ainsi, l'environnement LexicalEnvironment de l'exécution actuelle de l'utilisateur reste en mémoire. Toutes les variables de l'utilisateur sont également ses propriétés, de sorte qu'elles sont également conservées avec soin, et non mises à l'abri de la manière habituelle.

Le but est de s'assurer que si la fonction interne veut accéder à une variable externe dans le futur, elle peut le faire.

Résumer:

  1. La fonction interne conserve une référence à l'environnement LexicalEnvironment externe.
  2. La fonction interne peut accéder aux variables à partir de celle-ci à tout moment, même si la fonction externe est terminée.
  3. Le navigateur conserve le LexicalEnvironment et toutes ses propriétés (variables) en mémoire jusqu'à ce qu'une fonction interne le référence.

Ceci s'appelle une fermeture.


Comment je l'expliquerais à un enfant de six ans:

Vous savez comment les adultes peuvent posséder une maison, et ils appellent à la maison? Quand une mère a un enfant, l'enfant ne possède pas vraiment quelque chose, non? Mais ses parents possèdent une maison, alors chaque fois que quelqu'un demande à l'enfant "Où est ta maison?", Il / elle peut répondre à "cette maison!" Et indiquer la maison de ses parents. Une "fermeture" est la capacité de l'enfant à toujours (même à l'étranger) de pouvoir dire qu'il a une maison, même si c'est vraiment le parent qui est propriétaire de la maison.


L'homme de paille

J'ai besoin de savoir combien de fois un bouton a été cliqué et de faire quelque chose à chaque troisième clic ...

Solution assez évidente

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

Maintenant, cela fonctionnera, mais cela empiétera sur la portée externe en ajoutant une variable, dont le seul but est de garder une trace du nombre. Dans certains cas, cela serait préférable, car votre application externe pourrait avoir besoin d'accéder à ces informations. Mais dans ce cas, nous ne modifions que le comportement de chaque troisième clic. Il est donc préférable de placer cette fonctionnalité dans le gestionnaire d'événements .

Considérez cette option

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

Notez quelques petites choses ici.

Dans l'exemple ci-dessus, j'utilise le comportement de fermeture de JavaScript. Ce comportement permet à n'importe quelle fonction d'avoir accès à la portée dans laquelle elle a été créée, indéfiniment. Pour pratiquement l'appliquer, j'appelle immédiatement une fonction qui renvoie une autre fonction et, comme la fonction que je retourne a accès à la variable de comptage interne (en raison du comportement de fermeture expliqué ci-dessus), il en résulte une portée privée pour l'utilisation par le résultat. fonction ... Pas si simple? Diluons-le ...

Une simple fermeture d'une ligne

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

Toutes les variables en dehors de la fonction renvoyée sont disponibles pour la fonction renvoyée, mais elles ne le sont pas directement pour l'objet fonction renvoyé ...

func();  // Alerts "val"
func.a;  // Undefined

Trouver? Ainsi, dans notre exemple principal, la variable count est contenue dans la fermeture et toujours disponible pour le gestionnaire d'événements. Il conserve donc son état d'un clic à l'autre.

De plus, cet état de variable privée est entièrement accessible, à la fois pour les lectures et pour l'affectation à ses variables privées.

Voilà; vous intégrez maintenant pleinement ce comportement.

Article de blog complet (y compris les considérations relatives à jQuery)


Vous dormez et vous invitez Dan. Vous dites à Dan d'apporter un contrôleur XBox.

Dan invite Paul. Dan demande à Paul d'apporter un contrôleur. Combien de contrôleurs ont été amenés à la fête?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

Si nous prenons la question au sérieux, nous devrions découvrir ce qu’un enfant typique de 6 ans est capable d’acquérir sur le plan cognitif, même s’il est vrai que celui qui s’intéresse à JavaScript n’est pas si typique.

Sur le développement de l'enfant: 5 à 7 ans, il est écrit:

Votre enfant sera capable de suivre des instructions en deux étapes. Par exemple, si vous dites à votre enfant: "Va à la cuisine et apporte-moi un sac poubelle", ils pourront se souvenir de cette direction.

Nous pouvons utiliser cet exemple pour expliquer les fermetures, comme suit:

La cuisine est une fermeture qui a une variable locale, appelée trashBags . Dans la cuisine, une fonction appelée getTrashBag récupère un sac à ordures et le renvoie.

Nous pouvons coder cela en JavaScript comme ceci:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

Autres points expliquant pourquoi les fermetures sont intéressantes:

  • Chaque fois que makeKitchen() est appelée, une nouvelle fermeture est créée avec ses propres trashBags distincts.
  • La variable trashBags est locale à l'intérieur de chaque cuisine et n'est pas accessible à l'extérieur, mais la fonction interne de la propriété getTrashBag a accès.
  • Chaque appel de fonction crée une fermeture, mais il ne serait pas nécessaire de garder la fermeture sauf si une fonction interne, qui a accès à l'intérieur de la fermeture, peut être appelée de l'extérieur de la fermeture. Renvoyer l'objet avec la fonction getTrashBag fait ici.

Mon autre raison de choisir Node.js pour un nouveau projet est:

Être capable de faire du développement basé sur le cloud pur

J'ai utilisé Cloud9 IDE pendant un certain temps et je ne peux maintenant plus m'en passer, car il couvre tous les cycles de développement. Tout ce dont vous avez besoin est d’un navigateur et vous pouvez coder à tout moment n’importe où sur n’importe quel appareil. Vous n'avez pas besoin de saisir le code sur un ordinateur (comme à la maison), puis de le commander sur un autre ordinateur (comme au lieu de travail).

Bien sûr, il existe peut-être un IDE basé sur le cloud pour d’autres langues ou plates-formes (Cloud 9 IDE ajoute également des supports pour d’autres langues), mais utiliser Cloud 9 pour faire du développement Node.js est vraiment une expérience formidable pour moi.





javascript function variables scope closures