11
votes

Fermetures: Ligne par ligne Explication de "JavaScript: Good Parts" Exemple?

Je lis "JavaScript: les bonnes parties" et je suis totalement déroutée de ce qui se passe vraiment ici. Une explication plus détaillée et / ou simplifiée serait grandement appréciée. XXX PRE>

La fonction add_the_handlers code> est destiné à donner à chaque gestionnaire un numéro unique (I). Il échoue car les fonctions du gestionnaire sont liées à la variable i code>, pas la valeur de la variable i code> au moment de la fonction de la fonction: p>

// BETTER EXAMPLE

// Make a function that assigns event handler functions to an array of nodes the right way.
// When you click on a node, an alert box will display the ordinal of the node.

var add_the_handlers = function (nodes) {
    var i;
    for (i = 0; i < nodes.length; i += 1) {
        nodes[i].onclick = function (i) {
            return function (e) {
                alert(i);
            };
        }(i);
    }
};


2 commentaires

Voir les questions étiquetées dans: Stackoverflow.com/Questions/tagged/javascript+Closures+Loops


Vous pouvez également jouer avec une démo live JSBIN.com/Sezisalulede/1/edit ? html, js, sortie


4 Réponses :


3
votes

Tout est question de fermetures. Dans le premier exemple, "i" sera égal à "nœuds.length" pour chaque gestionnaire d'événements de clic, car il utilise "i" de la boucle qui crée les gestionnaires d'événements. Au moment où le gestionnaire d'événements est appelé, la boucle sera terminée, de sorte que "je" sera égale à "nœuds.length".

Dans le deuxième exemple, "I" est un paramètre (donc une variable locale). Les gestionnaires d'événements utiliseront la valeur de la variable locale "I" (le paramètre).


0 commentaires

0
votes

Cela a à voir avec la fermeture.

Lorsque vous faites la chose dans le mauvais exemple,

Lorsque vous cliquez sur chaque nœud, vous obtiendrez la dernière valeur I (c'est-à-dire que vous avez 3 nœuds, quel que soit le nœud que vous cliquez sur vous obtiendrez 2). Puisque votre alerte (i) est liée à une référence de variable I et non de la valeur de i au moment où elle était liée au gestionnaire d'événements.

Faire le meilleur exemple, vous l'avez lié à ce que je fais au moment où il a été itéré sur, alors cliquez sur le nœud 1 vous donnera 0, le nœud 2 vous donnera 1 et le noeud 3 vous donnera 2.

Fondamentalement, vous évaluez ce que je suis immédiatement quand il est appelé à la ligne} (i) et il est passé au paramètre e qui tient maintenant la valeur de ce que je suis à ce moment-là.

BTW ... Je pense qu'il y a une faute de frappe dans la meilleure partie d'exemple ... il devrait être alerte (E) au lieu d'alerte (i).


0 commentaires

2
votes

Dans les deux exemples, tout nœud qui est passé a un gestionnaire d'événements onclick lié à celui-ci (juste comme code>, qui est mauvais pratique après tout).

La différence est que dans le mauvais exemple, chaque fermeture (les fonctions du gestionnaire d'événements, c'est-à-dire) fait référence exacte à la variable exacte code> i code> en raison de leur portée parentale ordinaire. p>

Le bon exemple utilise une fonction anonyme qui est exécutée tout de suite. Cette fonction anonyme références exactement la même variable code> i code> comme dans le mauvais exemple, mais comme il est exécuté et fourni avec i code> comme premier paramètre, i code> La valeur de s est attribuée à une variable locale appelée ... hein? ... i code>, exactement - écrase donc celui défini dans la portée du parent. p>

Réécritons le bon exemple pour le faire clairement: P>

var add_the_handlers = function (nodes) {
    var i;
    for (i = 0; i < nodes.length; i += 1) {
        nodes[i].onclick = function (newvar) {
            return function (e) {
                alert(nevar);
            };
        }(i);
    }
};


1 commentaires

Typo in "alerte (Nevar)". Il devrait être "alerte (newvar)"



20
votes

Je pense que c'est une source de confusion très courante pour les nouveaux arrivants à JavaScript. D'abord, je suggérerais de vérifier l'article suivant Mozilla Dev Article de brève introduction sur le thème des fermetures et de la scorage lexical:

  • Mozilla Dev Centre: Utilisation de fermetures li> ul>

    Commençons par le mauvais: p>

    function makeOnClickCallback (x) {
       return function (e) {
          alert(x);
       };
    }
    
    for (i = 0; i < nodes.length; i += 1) {
       nodes[i].onclick = makeOnClickCallback(i);
    }
    


6 commentaires

Une question quelque peu liée. Que signifie "E" dans la fonction (e), et pourrait-il être remplacé par un var? J'avais l'habitude de penser que cela signifiait l'événement, mais maintenant je suis confus.


@Matrym: Oui, devrait être un argument que le navigateur passe à la fonction de rappel lorsque l'événement OnClick est soulevé. Consultez Cet article QuirksMode sur la manière dont cela est traité dans différents navigateurs.


Que se passe-t-il si nous n'utilisons pas une variable? Est-ce que nous passons donc nous pouvons chaîner des trucs?


@Matrym: Vous voulez dire pour le paramètre "e"? À moins que vous n'ayez besoin d'accéder à l'objet événement, vous n'avez pas besoin de ce paramètre. Vous ne pouvez même pas la définir: fonction de retour () {alerte (x); };


Qu'en est-il d'un violon pour la démo live du bon exemple jsbin.com/qoyuvecuju/1/ edit? JS, sortie et un pour le meilleur exemple jsbin.com/setaxegehote / 1 / Modifier? JS, Sortie


Rien comme une ligne d'une explication détaillée de la ligne, sont partis mes doutes. +100 si je pouvais