laissez-mot-clé dans la boucle for
ECMAScript 6 let
est censé fournir le bloc de portée sans levage des maux de tête. Certains peuvent-ils expliquer pourquoi, dans le code ci-dessous i
dans la fonction décide à la dernière valeur de la boucle (tout comme avec var
) au lieu de la valeur de l'itération en cours?
"use strict";
var things = {};
for (let i = 0; i < 3; i++) {
things["fun" + i] = function() {
console.log(i);
};
}
things["fun0"](); //prints 3
things["fun1"](); //prints 3
things["fun2"](); //prints 3
Selon MDN à l'aide de let
dans le for
boucle comme ça devrait lier la variable dans le champ d'application de la boucle du corps. Les choses fonctionnent comme j'imagine que quand j'utilise une variable temporaire à l'intérieur du bloc. Pourquoi est-ce nécessaire?
"use strict";
var things = {};
for (let i = 0; i < 3; i++) {
let index = i;
things["fun" + i] = function() {
console.log(index);
};
}
things["fun0"](); //prints 0
things["fun1"](); //prints 1
things["fun2"](); //prints 2
J'ai testé le script avec Traceur et node --harmony
.
- TL;DR: Le premier extrait de code montre un bug dans le code JavaScript de la mise en œuvre de l'environnement. C'est le bon comportement est à la sortie de 0, 1 et 2, au lieu de 3, 3 et 3. Les navigateurs modernes fonctionnent correctement et de sortie de 0, 1 et 2 lorsque vous exécutez le code.
- Apparemment, il ya trois différentes portées ici:
let x = 5; for (let x = 0; x < 10; x++) { let x = 3; console.log(x); }
Vous devez vous connecter pour publier un commentaire.
plisser les yeux la réponse est non plus up-to-date. Dans ECMA 6 spécification, ce comportement est que dans
i
obtient une nouvelle liaison pour chaque itération de la boucle.Cela signifie que chaque fermeture de la capture d'une autre
i
instance. Donc le résultat de012
est le résultat correct à partir de maintenant. Lorsque vous exécutez cette en Chrome v47+, vous obtenez le résultat correct. Lorsque vous l'exécutez dans IE11 et Edge, actuellement le résultat incorrect (333
) semble être produite.Plus d'informations concernant ce bug/feature peuvent être trouvés dans les liens dans cette page;
Depuis quand le
let
expression est utilisée, chaque itération crée une nouvelle portée lexicale enchaînés jusqu'à l'ancien périmètre. Cela a des implications sur les performances pour l'utilisation de lalet
expression, qui est rapporté ici.i
dans chaque itération de la boucle, toute modification dei
à l'intérieur de la boucle affecte encore le nombre d'itérations de la boucle. C'est une drôle de bête, moitié variable distincte, la moitié de référence à l'original.i
est copié dans une nouvelle variable locale c'est ce que vous faites référence à l'identificateuri
. À la fin de ce bloc, c'est recopiée dans la variable de boucle, qui dans la prochaine itération est copié vers le bas, etc. (Il y a un moyen plus efficace de mettre en œuvre, mais c'était le moyen le plus simple pour moi de penser à ce sujet)J'ai passé de ce code par Babel ainsi, nous pouvons comprendre le comportement en termes de familier ES5:
Voici le code transpiled à ES5:
Nous pouvons voir que les deux variables sont utilisées.
À l'extérieur de la portée
i
est la variable qui change en nous itération.Dans l'intérieur de la portée
_i
est une variable unique pour chaque itération. Il finira par être trois instances distinctes de_i
.Chaque fonction de rappel peut voir son correspondant
_i
, et pourrait même la manipuler si elle le voulait, indépendamment de la_i
s dans d'autres champs d'application.(Vous pouvez confirmer qu'il y a trois différents
_i
s en faisantconsole.log(i++)
à l'intérieur de la fonction de rappel. Changer_i
dans un précédent rappel n'affecte pas la sortie de rappels plus tard.)À la fin de chaque itération, la valeur de
_i
est copié dansi
. Donc de changer intérieure unique variable au cours de l'itération affectera l'extérieur itéré variable.Il est bon de voir que ES6 a continué la tradition de longue date de WTFJS.
for (let i = 0, ....)
crée un localement étenduei
qui n'est pas visible de l'extérieur de lafor
boucle. Le transpiled version ne unvar i
qui serait fonction de l'étendue. Qui ne semble pas être parfaitement représentative de la façon dont ES6+ fonctionne.const i = 5
vers le haut de la code. Babel sera alors sortie trois vars:i
,_i
et_i2
À mon humble avis -- les programmeurs qui, le premier, mis en œuvre ce SOIT (la production de votre version initiale de résultats) avait-elle correctement à l'égard de la santé mentale; ils peuvent ne pas avoir jeté un coup d'oeil à la spécification lors de la mise en œuvre.
Il fait plus de sens que d'une seule variable est utilisée, mais l'étendue de la boucle for. Surtout depuis que l'on doit se sentir libre de modifier cette variable en fonction des conditions à l'intérieur de la boucle.
Mais attendez-vous peut changement de la variable de boucle. WTFJS!! Toutefois, si vous essayez de le changer à l'intérieur de votre portée, il ne fonctionnera pas maintenant parce que c'est une nouvelle variable.
Je n'aime pas ce que j'ai à faire Pour obtenir ce que je veux (une seule variable est locale à l'):
Où à modifier la plus intuitive (si l'imaginaire) version pour gérer une nouvelle variable par itération:
Il est clair que mon intention avec la variable y est.. Ou l'aurait été si la santé mentale régné sur l'univers.
Votre premier exemple travaille maintenant dans FF; elle produit les 0, 1, 2. Vous arrivez à appeler le numéro fixe. J'appelle la question WTFJS.
ps. Ma référence à WTFJS est de JoeyTwiddle ci-dessus; Il sonne comme un mème je devrais avoir connu avant aujourd'hui, mais aujourd'hui était un grand moment pour l'apprendre.