var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value: " + i);
};
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
Il produit ceci:
Ma valeur: 3
Ma valeur: 3
Ma valeur: 3
Alors que je voudrais qu'il affiche:
Ma valeur: 0
Ma valeur: 1
Ma valeur: 2
Le même problème se produit lorsque le retard dans l'exécution de la fonction est provoqué par l'utilisation d'écouteurs d'événements:
var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
// as event listeners
buttons[i].addEventListener("click", function() {
// each should log its value.
console.log("My value: " + i);
});
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>
… Ou code asynchrone, par exemple en utilisant Promises:
// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));
for (var i = 0; i < 3; i++) {
// Log `i` as soon as each promise resolves.
wait(i * 100).then(() => console.log(i));
}
Edit: Il est également apparent dans for in
et for of
boucles:
const arr = [1,2,3];
const fns = [];
for(i in arr){
fns.push(() => console.log(`index: ${i}`));
}
for(v of arr){
fns.push(() => console.log(`value: ${v}`));
}
for(f of fns){
f();
}
Quelle est la solution à ce problème fondamental?
javascript
loops
closures
nickf
la source
la source
funcs
être un tableau, si vous utilisez des indices numériques? Juste un avertissement.Réponses:
Eh bien, le problème est que la variable
i
, dans chacune de vos fonctions anonymes, est liée à la même variable en dehors de la fonction.Solution classique: fermetures
Ce que vous voulez faire, c'est lier la variable de chaque fonction à une valeur distincte et immuable en dehors de la fonction:
Puisqu'il n'y a pas de portée de bloc dans JavaScript - seulement la portée de la fonction - en encapsulant la création de la fonction dans une nouvelle fonction, vous vous assurez que la valeur de "i" reste comme vous le vouliez.
Solution ES5.1: forEach
Avec la disponibilité relativement répandue de la
Array.prototype.forEach
fonction (en 2015), il convient de noter que dans les situations impliquant une itération principalement sur un tableau de valeurs,.forEach()
fournit un moyen propre et naturel d'obtenir une fermeture distincte pour chaque itération. Autrement dit, en supposant que vous disposez d'une sorte de tableau contenant des valeurs (références DOM, objets, etc.) et que le problème se pose de configurer des rappels spécifiques à chaque élément, vous pouvez le faire:L'idée est que chaque invocation de la fonction de rappel utilisée avec la
.forEach
boucle sera sa propre fermeture. Le paramètre transmis à ce gestionnaire est l'élément de tableau spécifique à cette étape particulière de l'itération. S'il est utilisé dans un rappel asynchrone, il n'entrera en collision avec aucun des autres rappels établis aux autres étapes de l'itération.S'il vous arrive de travailler dans jQuery, la
$.each()
fonction vous donne une capacité similaire.Solution ES6:
let
ECMAScript 6 (ES6) lance une nouvelle
let
et desconst
mots - clés qui sont différentes que la portée se lesvar
variables à base. Par exemple, dans une boucle avec unlet
index basé sur, chaque itération à travers la boucle aura une nouvelle variablei
avec une portée de boucle, donc votre code fonctionnera comme vous vous y attendez. Il existe de nombreuses ressources, mais je recommanderais le post de portée de bloc de 2ality comme une excellente source d'informations.Attention, cependant, IE9-IE11 et Edge avant la prise en charge d'Edge 14
let
mais se trompent (ils n'en créent pas ài
chaque fois, donc toutes les fonctions ci-dessus enregistreraient 3 comme si nous les utilisionsvar
). Edge 14 réussit enfin.la source
function createfunc(i) { return function() { console.log("My value: " + i); }; }
encore fermé car il utilise la variablei
?Function.bind()
est définitivement préférable maintenant, voir stackoverflow.com/a/19323214/785541 ..bind()
est "la bonne réponse" n'est pas juste. Ils ont chacun leur place. Avec.bind()
vous ne pouvez pas lier d'arguments sans lier lathis
valeur. Vous obtenez également une copie de l'i
argument sans la possibilité de le muter entre les appels, ce qui est parfois nécessaire. Ce sont donc des constructions très différentes, sans compter que les.bind()
implémentations ont été historiquement lentes. Bien sûr, dans l'exemple simple, cela fonctionnerait, mais les fermetures sont un concept important à comprendre, et c'est de cela qu'il s'agissait.Essayer:
Modifier (2014):
Personnellement, je pense que la réponse
.bind
la plus récente de @ Aust sur l'utilisation est la meilleure façon de faire ce genre de chose maintenant. Il y a aussi lo tableau de bord / underscore est_.partial
quand vous n'avez pas besoin ou si vous voulez jouer avecbind
« sthisArg
.la source
}(i));
?i
comme argumentindex
à la fonction.Un autre moyen qui n'a pas encore été mentionné est l'utilisation de
Function.prototype.bind
MISE À JOUR
Comme indiqué par @squint et @mekdev, vous obtenez de meilleures performances en créant d'abord la fonction en dehors de la boucle, puis en liant les résultats dans la boucle.
la source
_.partial
.bind()
sera largement obsolète avec les fonctionnalités d'ECMAScript 6. En outre, cela crée en fait deux fonctions par itération. D'abord l'anonyme, puis celui généré par.bind()
. Une meilleure utilisation serait de le créer à l'extérieur de la boucle, puis.bind()
à l'intérieur.bind
est utilisé. J'ai ajouté un autre exemple selon vos suggestions.this
.À l'aide d'une expression de fonction immédiatement invoquée , la manière la plus simple et la plus lisible pour entourer une variable d'index:
Cela envoie l'itérateur
i
dans la fonction anonyme que nous définissons commeindex
. Cela crée une fermeture, où la variablei
est enregistrée pour une utilisation ultérieure dans toute fonctionnalité asynchrone au sein de l'IIFE.la source
i
est quoi, je renommerais le paramètre de fonction enindex
.index
place dei
.var funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() {console.log('iterator: ' + index);}; })(i); }; for (var j = 0; j < 3; j++) { funcs[j](); }
.forEach()
, mais la plupart du temps, quand on commence avec un tableau,forEach()
c'est un bon choix, comme:var nums [4, 6, 7]; var funcs = {}; nums.forEach(function (num, i) { funcs[i] = function () { console.log(num); }; });
Un peu tard pour la fête, mais j'explorais ce problème aujourd'hui et j'ai remarqué que la plupart des réponses ne traitent pas complètement de la façon dont Javascript traite les portées, ce qui est essentiellement ce que cela se résume.
Ainsi, comme beaucoup d'autres l'ont mentionné, le problème est que la fonction interne fait référence à la même
i
variable. Alors pourquoi ne créons-nous pas simplement une nouvelle variable locale à chaque itération, et avons-nous la référence de fonction interne à la place?Tout comme auparavant, où chaque fonction interne a sorti la dernière valeur assignée à
i
, maintenant chaque fonction interne sort juste la dernière valeur assignée àilocal
. Mais chaque itération ne devrait-elle pas avoir la sienneilocal
?Il s'avère que c'est le problème. Chaque itération partage la même étendue, donc chaque itération après la première n'est que l'écrasement
ilocal
. De MDN :Réitéré pour souligner:
Nous pouvons le voir en vérifiant
ilocal
avant de le déclarer à chaque itération:C'est exactement pourquoi ce bug est si délicat. Même si vous redéclarez une variable, Javascript ne lancera pas d'erreur et JSLint ne lancera même pas d'avertissement. C'est aussi pourquoi la meilleure façon de résoudre ce problème est de tirer parti des fermetures, ce qui est essentiellement l'idée qu'en Javascript, les fonctions internes ont accès aux variables externes car les portées internes "renferment" les portées externes.
Cela signifie également que les fonctions internes "conservent" les variables externes et les maintiennent en vie, même si la fonction externe revient. Pour utiliser cela, nous créons et appelons une fonction wrapper uniquement pour créer une nouvelle portée, déclarons
ilocal
dans la nouvelle portée et retournons une fonction interne qui utiliseilocal
(plus d'explications ci-dessous):La création de la fonction interne à l'intérieur d'une fonction wrapper donne à la fonction interne un environnement privé auquel elle seule peut accéder, une "fermeture". Ainsi, chaque fois que nous appelons la fonction wrapper, nous créons une nouvelle fonction interne avec son propre environnement séparé, garantissant que les
ilocal
variables ne se heurtent pas et ne se remplacent pas. Quelques optimisations mineures donnent la réponse finale que de nombreux autres utilisateurs de SO ont donnée:Mise à jour
Avec ES6 désormais intégré, nous pouvons désormais utiliser le nouveau
let
mot clé pour créer des variables de portée bloc:Regardez comme c'est facile maintenant! Pour plus d'informations, consultez cette réponse , sur laquelle mes informations sont basées.
la source
let
-const
clés et . Si cette réponse devait s'élargir pour l'inclure, elle serait beaucoup plus utile à l'échelle mondiale à mon avis.let
et lié une explication plus complètei=0; while(i < 100) { setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000); setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000); i++ }
? (pourrait remplacer window.open () par getelementbyid ......)i
vos fonctions de temporisation, vous n'avez donc pas besoin de fermetureL'ES6 étant désormais largement pris en charge, la meilleure réponse à cette question a changé. ES6 fournit les mots clés
let
etconst
pour cette circonstance exacte. Au lieu de jouer avec les fermetures, nous pouvons simplement utiliserlet
pour définir une variable d'étendue de boucle comme ceci:val
pointera ensuite sur un objet spécifique à ce tour particulier de la boucle et renverra la valeur correcte sans la notation de fermeture supplémentaire. Cela simplifie évidemment considérablement ce problème.const
est similaire àlet
la restriction supplémentaire selon laquelle le nom de variable ne peut pas être renvoyé à une nouvelle référence après l'affectation initiale.La prise en charge du navigateur est désormais disponible pour ceux qui ciblent les dernières versions des navigateurs.
const
/let
sont actuellement pris en charge dans les derniers Firefox, Safari, Edge et Chrome. Il est également pris en charge dans Node, et vous pouvez l'utiliser n'importe où en tirant parti d'outils de construction comme Babel. Vous pouvez voir un exemple de travail ici: http://jsfiddle.net/ben336/rbU4t/2/Documents ici:
Attention, cependant, IE9-IE11 et Edge avant la prise en charge d'Edge 14
let
mais se trompent (ils n'en créent pas ài
chaque fois, donc toutes les fonctions ci-dessus enregistreraient 3 comme si nous les utilisionsvar
). Edge 14 réussit enfin.la source
Une autre façon de le dire est que le
i
dans votre fonction est lié au moment de l'exécution de la fonction, pas au moment de la création de la fonction.Lorsque vous créez la fermeture,
i
est une référence à la variable définie dans la portée extérieure, et non une copie de celle-ci telle qu'elle était lorsque vous avez créé la fermeture. Il sera évalué au moment de l'exécution.La plupart des autres réponses fournissent des moyens de contourner le problème en créant une autre variable qui ne changera pas la valeur pour vous.
Je pensais juste ajouter une explication pour plus de clarté. Pour une solution, personnellement, j'irais avec Harto car c'est la façon la plus explicite de le faire à partir des réponses ici. N'importe quel code publié fonctionnera, mais j'opterais pour une usine de fermeture plutôt que d'avoir à écrire une pile de commentaires pour expliquer pourquoi je déclare une nouvelle variable (Freddy et 1800) ou si j'ai une étrange syntaxe de fermeture intégrée (apphacker).
la source
Ce que vous devez comprendre, c'est que la portée des variables en javascript est basée sur la fonction. C'est une différence importante que disons c # où vous avez une portée de bloc, et simplement copier la variable dans une à l'intérieur du for fonctionnera.
L'encapsuler dans une fonction qui évalue le retour de la fonction comme la réponse d'Apphacker fera l'affaire, car la variable a maintenant la portée de la fonction.
Il existe également un mot clé let au lieu de var, qui permettrait d'utiliser la règle d'étendue de bloc. Dans ce cas, définir une variable à l'intérieur du for ferait l'affaire. Cela dit, le mot clé let n'est pas une solution pratique en raison de la compatibilité.
la source
Voici une autre variante de la technique, similaire à celle de Bjorn (apphacker), qui vous permet d'affecter la valeur de la variable à l'intérieur de la fonction plutôt que de la passer en paramètre, ce qui peut parfois être plus clair:
Notez que quelle que soit la technique que vous utilisez, la
index
variable devient une sorte de variable statique, liée à la copie retournée de la fonction interne. C'est-à-dire que les modifications de sa valeur sont conservées entre les appels. Cela peut être très pratique.la source
var
ligne et lareturn
ligne ne fonctionnerait pas? Merci!var
et quereturn
la variable ne serait pas affectée avant d'avoir renvoyé la fonction interne.Ceci décrit l'erreur courante lors de l'utilisation de fermetures en JavaScript.
Une fonction définit un nouvel environnement
Considérer:
Pour chaque
makeCounter
invocation,{counter: 0}
un nouvel objet est créé. De plus, une nouvelle copie deobj
est également créée pour référencer le nouvel objet. Ainsi,counter1
etcounter2
sont indépendants les uns des autres.Fermetures en boucles
L'utilisation d'une fermeture dans une boucle est délicate.
Considérer:
Notez que
counters[0]
et necounters[1]
sont pas indépendants. En fait, ils fonctionnent sur le mêmeobj
!En effet, il n'y a qu'une seule copie de
obj
partagée sur toutes les itérations de la boucle, peut-être pour des raisons de performances. Même si{counter: 0}
un nouvel objet est créé à chaque itération, la même copie deobj
sera simplement mise à jour avec une référence à l'objet le plus récent.La solution consiste à utiliser une autre fonction d'assistance:
Cela fonctionne parce que les variables locales dans l'étendue de la fonction directement, ainsi que les variables d'argument de fonction, se voient allouer de nouvelles copies à l'entrée.
la source
var obj = {counter: 0};
est évaluée avant l'exécution de tout code, comme indiqué dans: MDN var : les déclarations var, où qu'elles se produisent, sont traitées avant l'exécution de tout code.La solution la plus simple serait,
À la place d'utiliser:
qui alerte "2", 3 fois. En effet, les fonctions anonymes créées dans la boucle for partagent la même fermeture et, dans cette fermeture, la valeur de
i
est la même. Utilisez ceci pour empêcher la fermeture partagée:L'idée derrière cela est d'encapsuler le corps entier de la boucle for avec une IIFE (Immediateely Invoked Function Expression) et de passer
new_i
en paramètre et de le capturer en tant quei
. Étant donné que la fonction anonyme est exécutée immédiatement, lei
valeur est différente pour chaque fonction définie à l'intérieur de la fonction anonyme.Cette solution semble répondre à un tel problème car elle nécessitera des modifications minimes du code d'origine souffrant de ce problème. En fait, c'est par conception, cela ne devrait pas être un problème du tout!
la source
essayez celui-ci plus court
pas de tableau
pas de supplément pour la boucle
http://jsfiddle.net/7P6EN/
la source
Voici une solution simple qui utilise
forEach
(fonctionne sur IE9):Tirages:
la source
Le principal problème avec le code affiché par l'OP est qu'il
i
n'est jamais lu jusqu'à la deuxième boucle. Pour démontrer, imaginez voir une erreur à l'intérieur du codeL'erreur ne se produit pas tant qu'elle
funcs[someIndex]
n'est pas exécutée()
. En utilisant cette même logique, il devrait être évident que la valeur dei
n'est pas non plus collectée avant ce point non plus. Une fois que les finitions de boucle d' origine,i++
apportei
à la valeur3
qui se traduit par la conditioni < 3
défaillante et la boucle sans fin. À ce stade,i
est3
et donc quandfuncs[someIndex]()
est utilisé, eti
évalué, il est 3 - à chaque fois.Pour dépasser cela, vous devez évaluer au
i
fur et à mesure qu'il se produit. Notez que cela s'est déjà produit sous forme defuncs[i]
(où il y a 3 index uniques). Il existe plusieurs façons de capturer cette valeur. La première consiste à le passer en paramètre à une fonction qui est déjà présentée de plusieurs façons ici.Une autre option consiste à construire un objet fonction qui pourra se refermer sur la variable. Cela peut être accompli ainsi
jsFiddle Demo
la source
Les fonctions JavaScript "ferment" la portée à laquelle elles ont accès lors de la déclaration et conservent l'accès à cette portée même lorsque les variables de cette portée changent.
Chaque fonction du tableau ci-dessus se ferme sur la portée globale (globale, simplement parce que c'est la portée dans laquelle ils sont déclarés).
Plus tard, ces fonctions sont appelées à enregistrer la valeur la plus récente de
i
dans la portée globale. C'est la magie et la frustration de la fermeture."Les fonctions JavaScript se ferment sur la portée dans laquelle elles sont déclarées et conservent l'accès à cette portée même lorsque les valeurs des variables à l'intérieur de cette portée changent."
Utiliser
let
au lieu devar
résout cela en créant une nouvelle portée à chaquefor
exécution de la boucle, en créant une portée séparée pour chaque fonction à fermer. Diverses autres techniques font la même chose avec des fonctions supplémentaires.(
let
rend le bloc de variables limité. Les blocs sont indiqués par des accolades, mais dans le cas de la boucle for, la variable d'initialisation,i
dans notre cas, est considérée comme déclarée dans les accolades.)la source
i
est fixée à la portée mondiale. Lorsque lafor
boucle se termine, la valeur globale dei
est maintenant 3. Par conséquent, chaque fois que cette fonction est invoquée dans le tableau (en utilisant, disonsfuncs[j]
),i
dans cette fonction fait référence à lai
variable globale (qui est 3).Après avoir lu diverses solutions, j'aimerais ajouter que la raison pour laquelle ces solutions fonctionnent est de s'appuyer sur le concept de chaîne de portée . C'est la façon dont JavaScript résout une variable pendant l'exécution.
var
et sonarguments
.window
.Dans le code initial:
Une fois
funcs
exécuté, la chaîne de portée serafunction inner -> global
. Étant donné que la variablei
ne peut pas être trouvée dansfunction inner
(ni déclarée à l'aidevar
ni passée comme arguments), elle continue de rechercher, jusqu'à ce que la valeur dei
soit finalement trouvée dans la portée globale qui estwindow.i
.En l'enveloppant dans une fonction externe, définissez explicitement une fonction d'aide comme l'a fait harto ou utilisez une fonction anonyme comme l'a fait Bjorn :
Une fois
funcs
exécuté, la chaîne de portée le sera désormaisfunction inner -> function outer
. Cette heurei
peut être trouvée dans la portée de la fonction externe qui est exécutée 3 fois dans la boucle for, chaque fois que la valeur esti
liée correctement. Il n'utilisera pas la valeur dewindow.i
l'exécution interne.Plus de détails peuvent être trouvés ici.
Cela inclut l'erreur courante de créer une fermeture dans la boucle comme ce que nous avons ici, ainsi que la raison pour laquelle nous avons besoin d'une fermeture et de la performance.
la source
Array.prototype.forEach(function callback(el) {})
naturellement fonctionnent: le rappel qui est passé en forme naturellement la portée de l'habillage avec el correctement lié à chaque itération deforEach
. Ainsi, chaque fonction interne définie dans le rappel pourra utiliser la bonneel
valeurAvec les nouvelles fonctionnalités de l'ES6, la portée au niveau du bloc est gérée:
Le code de la question OP est remplacé par
let
au lieu devar
.la source
const
fournit le même résultat et doit être utilisé lorsque la valeur d'une variable ne change pas. Cependant, l'utilisation de l'const
intérieur de l'initialiseur de la boucle for n'est pas implémentée correctement dans Firefox et n'a pas encore été corrigée. Au lieu d'être déclaré à l'intérieur du bloc, il est déclaré à l'extérieur du bloc, ce qui entraîne une redéclaration de la variable, ce qui entraîne à son tour une erreur. L'utilisation de l'let
intérieur de l'initialiseur est correctement implémentée dans Firefox, donc ne vous inquiétez pas.Je suis surpris que personne n'ait encore suggéré d'utiliser la
forEach
fonction pour mieux éviter de (ré) utiliser des variables locales. En fait, je n'utilisefor(var i ...)
plus du tout pour cette raison.// modifié pour utiliser à la
forEach
place de la carte.la source
.forEach()
est une bien meilleure option si vous ne cartographiez rien, et Daryl l'a suggéré 7 mois avant de publier, donc il n'y a rien à être surpris.Cette question montre vraiment l'histoire de JavaScript! Maintenant, nous pouvons éviter la portée des blocs avec les fonctions fléchées et gérer les boucles directement à partir des nœuds DOM à l'aide des méthodes Object.
la source
La raison pour laquelle votre exemple d'origine n'a pas fonctionné est que toutes les fermetures que vous avez créées dans la boucle faisaient référence au même cadre. En effet, avoir 3 méthodes sur un objet avec une seule
i
variable. Ils ont tous imprimé la même valeur.la source
Tout d'abord, comprenez ce qui ne va pas avec ce code:
Ici, lorsque le
funcs[]
tableau est en cours d'initialisation,i
est incrémenté, lefuncs
tableau est initialisé et la taille dufunc
tableau devient 3, donci = 3,
. Maintenant, lorsque lefuncs[j]()
est appelé, il utilise à nouveau la variablei
, qui a déjà été incrémentée à 3.Maintenant, pour résoudre ce problème, nous avons de nombreuses options. En voici deux:
Nous pouvons initialiser
i
aveclet
ou initialiser une nouvelle variableindex
aveclet
et la rendre égale ài
. Ainsi, lorsque l'appel est en cours,index
sera utilisé et sa portée se terminera après l'initialisation. Et pour appeler,index
sera à nouveau initialisé:Une autre option peut être d'introduire un
tempFunc
qui renvoie la fonction réelle:la source
Utilisez une structure de fermeture , cela réduirait votre supplément de boucle. Vous pouvez le faire en une seule boucle for:
la source
Cas 1 : utilisation
var
Ouvrez maintenant la fenêtre de votre console Chrome en appuyant sur F12 et actualisez la page. Développer toutes les 3 fonctions à l'intérieur du tableau.Vous verrez une propriété appelée
[[Scopes]]
.Agrandir celle-ci. Vous verrez un objet tableau appelé"Global"
, développez-le. Vous trouverez une propriété'i'
déclarée dans l'objet qui a la valeur 3.Conclusion:
'var'
dehors d'une fonction, elle devient une variable globale (vous pouvez vérifier en tapanti
ouwindow.i
dans la fenêtre de la console. Elle renverra 3).console.log("My value: " + i)
prend la valeur de sonGlobal
objet et affiche le résultat.CAS2: utilisation de let
Remplacez maintenant le
'var'
par'let'
Faites la même chose, allez dans les étendues. Vous verrez maintenant deux objets
"Block"
et"Global"
. Maintenant, développez l'Block
objet, vous verrez que «i» y est défini, et l'étrange est que, pour chaque fonction, la valeur ifi
est différente (0, 1, 2).Conclusion:
Lorsque vous déclarez une variable en utilisant
'let'
même en dehors de la fonction mais à l'intérieur de la boucle, cette variable ne sera pas une variable globale, elle deviendra uneBlock
variable de niveau qui n'est disponible que pour la même fonction. C'est la raison pour laquelle nous obtenons une valeuri
différente pour chaque fonction lorsque nous invoquons les fonctions.Pour plus de détails sur le fonctionnement plus proche, veuillez consulter le didacticiel vidéo génial https://youtu.be/71AtaJpJHw0
la source
Vous pouvez utiliser un module déclaratif pour les listes de données telles que query-js (*). Dans ces situations, je trouve personnellement une approche déclarative moins surprenante
Vous pouvez ensuite utiliser votre deuxième boucle et obtenir le résultat attendu ou vous pouvez le faire
(*) Je suis l'auteur de query-js et donc partisan de son utilisation, alors ne prenez pas mes mots comme recommandation pour ladite bibliothèque uniquement pour l'approche déclarative :)
la source
Query.range(0,3)
? Cela ne fait pas partie des balises de cette question. De plus, si vous utilisez une bibliothèque tierce, vous pouvez fournir le lien de la documentation.Je préfère utiliser la
forEach
fonction, qui a sa propre fermeture avec la création d'une pseudo-plage:Cela semble plus laid que les gammes dans d'autres langues, mais à mon humble avis moins monstrueux que d'autres solutions.
la source
Et encore une autre solution: au lieu de créer une autre boucle, liez simplement le
this
à la fonction de retour.En liant cela , résout également le problème.
la source
De nombreuses solutions semblent correctes, mais elles ne mentionnent pas son nom,
Currying
qui est un modèle de conception de programmation fonctionnelle pour des situations comme ici. 3 à 10 fois plus rapide que bind en fonction du navigateur.Voir le gain de performances dans différents navigateurs .
la source
Votre code ne fonctionne pas, car il fait:
Maintenant, la question est, quelle est la valeur de variable
i
lorsque la fonction est appelée? Étant donné que la première boucle est créée avec la condition dei < 3
, elle s'arrête immédiatement lorsque la condition est fausse, ce qui est le casi = 3
.Vous devez comprendre que, au moment où vos fonctions sont créées, aucun de leur code n'est exécuté, il n'est enregistré que pour plus tard. Et donc quand ils sont appelés plus tard, l'interprète les exécute et demande: "Quelle est la valeur actuelle de
i
?"Ainsi, votre objectif est d'enregistrer d'abord la valeur de
i
pour fonctionner et uniquement après cela, d'enregistrer la fonction dansfuncs
. Cela pourrait être fait par exemple de cette façon:De cette façon, chaque fonction aura sa propre variable
x
et nous la mettonsx
à la valeur dei
dans chaque itération.Ce n'est qu'une des multiples façons de résoudre ce problème.
la source
la source
Utilisez let (portée bloquée) au lieu de var.
la source