La fameuse Boucle Javascript? [dupliquer]
cette question a déjà une réponse ici:
j'ai le code suivant.
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function () {
alert(i);
};
document.body.appendChild(link);
}
}
le code ci-dessus est pour générer 5 liens et lier chaque lien avec un événement d'alerte pour afficher l'id du lien courant. Mais Ça ne fonctionne pas. Lorsque vous cliquez sur les liens générés, ils disent tous "lien 5".
mais les codes suivants fonctionnent comme notre attente.
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function (num) {
return function () {
alert(num);
};
}(i);
document.body.appendChild(link);
}
}
les 2 extraits ci-dessus sont cités de ici . Comme l'explique l'auteur, semble le fermeture fait la magie.
mais comment cela fonctionne et comment fermeture qui sont tous au-delà de ma compréhension. Pourquoi le premier ne fonctionne pas, alors que le second fonctionne? Quelqu'un peut-il donner une explication détaillée de la magie?
merci.
5 réponses
me citant pour une explication du premier exemple:
inefficace car deux nouveaux objets de fonction doivent être créés pour chaque lien. Cela n'est pas nécessaire, car ils peuvent facilement être partagés si vous utilisez le noeud DOM pour le stockage de l'information:les portées JavaScript sont au niveau de la fonction, pas au niveau du bloc, et la création d'une fermeture signifie simplement que la portée enveloppante est ajoutée à l'environnement lexical de la fonction incluse.
après la boucle se termine, la variable de niveau de fonction i a la valeur 5, et c'est ce que la fonction interne 'voit'.
function linkListener() {
alert(this.i);
}
function addLinks () {
for(var i = 0; i < 5; ++i) {
var link = document.createElement('a');
link.appendChild(document.createTextNode('Link ' + i));
link.i = i;
link.onclick = linkListener;
document.body.appendChild(link);
}
}
j'aime écrire des explications simples pour les gens épais, parce que je suis épais alors voilà ...
nous avons 5 divs sur la page, chacun avec un ID ... div1, div2, div3, div4, div5
jQuery peut le faire ...
for (var i=1; i<=5; i++) {
$("#div" + i).click ( function() { alert ($(this).index()) } )
}
mais en abordant vraiment le problème (et en le construisant lentement) ...
STEP 1
for (var i=1; i<=5; i++) {
$("#div" + i).click (
// TODO: Write function to handle click event
)
}
STEP 2
for (var i=1; i<=5; i++) {
$("#div" + i).click (
function(num) {
// A functions variable values are set WHEN THE FUNCTION IS CALLED!
// PLEASE UNDERSTAND THIS AND YOU ARE HOME AND DRY (took me 2 years)!
// Now the click event is expecting a function as a handler so return it
return function() { alert (num) }
}(i) // We call the function here, passing in i
)
}
SIMPLE À COMPRENDRE ALTERNATIVE
si vous ne pouvez pas avoir votre tête autour de cela, alors cela devrait être plus facile à comprendre et a le même effet ...
for (var i=1; i<=5; i++) {
function clickHandler(num) {
$("#div" + i).click (
function() { alert (num) }
)
}
clickHandler(i);
}
cela devrait être simple à comprendre si vous vous souvenez qu'une fonction variable valeurs sont définies lorsque la fonction est appelée (mais cela utilise le même processus de pensée exacte qu'avant)
en gros, dans le premier exemple, vous liez le i
à l'intérieur du handler onclick
directement au i
à l'extérieur du handler onclick
. Ainsi, lorsque le manipulateur i
à l'extérieur du manipulateur onclick
change, le manipulateur i
à l'intérieur du manipulateur onclick
change aussi.
dans le second exemple, au lieu de le lier au num
dans le handler onclick
, vous le passez dans une fonction, qui le lie ensuite au num
dans le onclick
gestionnaire. Lorsque vous le passez dans la fonction, la valeur de i
est copié, non lié à num
. Donc quand i
change, num
reste le même. La copie se produit parce que les fonctions en JavaScript sont des "fermetures", ce qui signifie qu'une fois que quelque chose est passé dans la fonction, il est" fermé " pour la modification externe.
D'autres ont expliqué ce qui se passe, voici une solution alternative.
function addLinks () {
for (var i = 0, link; i < 5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
with ({ n: i }) {
link.onclick = function() {
alert(n);
};
}
document.body.appendChild(link);
}
}
essentiellement les pauvres hommes let-binding.
dans le premier exemple, vous liez simplement cette fonction à l'événement onclick:
function() {alert(i);};
Cela signifie que sur l'événement click js devrait alerter la valeur de la addlink fonctions d'une variable. Sa valeur sera 5 à cause de la boucle for().
dans le deuxième exemple, vous générez une fonction à lier avec une autre fonction:
function (num) {
return function () { alert(num); };
}
cela signifie: Si appelé avec une valeur, me rendre une fonction qui va alerter la valeur d'entrée. Par exemple: en appelant function(3)
, vous obtiendrez function() { alert(3) };
.
vous appelez cette fonction avec la valeur i à chaque itération, donc vous créez des fonctions onclick séparées pour chaque lien.
le point est que dans le premier exemple votre fonction contenait une référence variable, tandis que dans le second avec l'aide de la fonction externe vous substitué la référence avec une valeur réelle. Cela s'appelle une fermeture en gros parce que vous " enfermez" la valeur courante d'une variable dans votre fonction au lieu de garder une référence à elle.