La fonction JavaScript de déclaration et d'évaluation afin
Pourquoi le premier de ces exemples fonctionnent pas, mais tous les autres ne le font?
//1 - does not work
(function() {
setTimeout(someFunction1, 10);
var someFunction1 = function() { alert('here1'); };
})();
//2
(function() {
setTimeout(someFunction2, 10);
function someFunction2() { alert('here2'); }
})();
//3
(function() {
setTimeout(function() { someFunction3(); }, 10);
var someFunction3 = function() { alert('here3'); };
})();
//4
(function() {
setTimeout(function() { someFunction4(); }, 10);
function someFunction4() { alert('here4'); }
})();
Vous devez vous connecter pour publier un commentaire.
Ce n'est ni une portée de problème, ni est-il un problème la fermeture. Le problème est dans la compréhension entre déclarations et expressions.
Code JavaScript, car même Netscape, une première version de JavaScript et de Microsoft de la première copie de celle-ci est traitée en deux phases:
Phase 1: compilation - dans cette phase, le code est compilé dans un arbre de syntaxe (et de pseudo-code binaire ou binaire en fonction du moteur).
Phase 2: exécution de l'analyse de code est alors interprétée.
La syntaxe de la fonction déclaration est:
Arguments sont des cours en option (code est facultatif, mais quel est l'intérêt de qui?).
Mais JavaScript vous permet également de créer des fonctions à l'aide de expressions. La syntaxe pour les expressions de fonction sont similaires pour les déclarations de fonction, sauf qu'ils sont écrits dans le contexte d'expression. Et les expressions sont:
=
signe (ou:
sur l'objet de littéraux).()
.Expressions contrairement à déclarations sont traitées dans la phase d'exécution plutôt que de la phase de compilation. Et de ce fait, l'ordre des expressions de la matière.
Donc, pour clarifier:
Phase 1: compilation. Le compilateur voit que la variable
someFunction
est défini de sorte qu'il crée. Par défaut, toutes les variables créées ont la valeur undefined. Notez que le compilateur ne peut pas affecter des valeurs encore à ce stade car les valeurs peuvent avoir besoin de l'interpréteur pour exécuter un code pour renvoyer une valeur à attribuer. Et à ce stade, nous ne sommes pas encore à l'exécution de code.Phase 2: de l'exécution. L'interprète voit que vous souhaitez passer la variable
someFunction
à setTimeout. Et il le fait. Malheureusement, la valeur actuelle desomeFunction
est pas défini.Phase 1: compilation. Le compilateur voit de déclarer une fonction avec le nom someFunction et de sorte qu'il crée.
Phase 2: L'interprète voit que vous souhaitez passer
someFunction
pour le setTimeout. Et il le fait. La valeur actuelle desomeFunction
est sa fonction compilée déclaration.Phase 1: compilation. Le compilateur voit que vous avez déclaré une variable
someFunction
et il crée. Comme avant, sa valeur est undefined.Phase 2: de l'exécution. L'interprète passe d'une fonction anonyme pour setTimeout pour être exécuté au plus tard. Dans cette fonction, il vous voit, vous êtes à l'aide de la variable
someFunction
de sorte qu'il crée une fermeture à la variable. À ce stade, la valeur desomeFunction
est toujours pas défini. Ensuite, il vous voit assigner une fonction àsomeFunction
. À ce stade, la valeur desomeFunction
n'est plus défini. 1/100e de seconde plus tard, le setTimeout les déclencheurs et les someFunction est appelé. Depuis sa valeur n'est plus indéfini, il fonctionne.Cas 4 est vraiment une autre version de cas 2 avec un peu de cas 3 jeté dans. Au point
someFunction
est passé à setTimeout il existe déjà dû être déclaré.Précisions supplémentaires:
Vous pouvez vous demander pourquoi
setTimeout(someFunction, 10)
ne crée pas de clôture entre la copie locale de someFunction et l'on est passé à setTimeout. La réponse à cela est que les arguments d'une fonction en JavaScript sont toujours, toujours passé par valeur, s'ils sont des nombres ou des chaînes ou par référence pour tout le reste. Donc setTimeout ne sont pas la variable someFunction passée (ce qui aurait signifié une fermeture en cours de création), mais ne reçoit que de l'objet qui someFunction fait référence (qui dans ce cas est une fonction). C'est le plus largement utilisé mécanisme en JavaScript pour rupture de fermeture (par exemple dans les boucles).name and arguments are of course optional
dans votre fonctiondefinition
explication. Maintenant que c'est confus.. MDN, MSDN, ES3, ES5 et tous les livres que j'ai lus, contredisent cette affirmation et dire que seuls les arguments sont facultatifs dans une déclaration de fonction:function Identifier ( FormalParameterList opt ){ FunctionBody }
(si l'identifiant est obligatoire), mais FunctionExpression :function Identifier opt ( FormalParameterList opt ){ FunctionBody }
Donc, ce qui me manque?Javascript portée de la fonction de base, pas strictement une portée lexicale. cela signifie que
Somefunction1 est défini à partir du début de la fonction englobante, mais son contenu n'est pas défini jusqu'à ce que assigné.
dans le deuxième exemple, l'affectation est la partie de la déclaration, de sorte qu'il "bouge" vers le haut.
dans le troisième exemple, la variable existe quand l'anonyme intérieure fermeture est défini, mais il n'est pas utilisé jusqu'à ce que 10 secondes plus tard, alors que la valeur a été attribuée.
quatrième exemple est à la fois de la deuxième et troisième raisons de travailler
someFunction1
?Parce que
someFunction1
n'a pas encore été attribué au moment de l'appel àsetTimeout()
est exécutée.someFunction3 peut ressembler à un cas similaire, mais puisque vous êtes de passage à une fonction d'emballage
someFunction3()
àsetTimeout()
dans ce cas, l'appel àsomeFunction3()
n'est pas évalué à plus tard.someFunction2
n'a pas encore été attribué lors de l'appel àsetTimeout()
est exécuté soit...?function
mot-clé n'est pas exactement équivalent à l'attribution d'une fonction anonyme pour une variable. Les fonctions déclarées commefunction foo()
sont "hissé" au début de la portée actuelle, alors que les affectations de variables au point où ils sont écrits.Cela sonne comme une base de suivre la bonne procédure pour rester hors de l'ennui. Déclarer des variables et des fonctions avant de les utiliser et de déclarer des fonctions comme ceci:
Éviter de déclarer avec var. C'est tout simplement bâclée et conduit à des problèmes. Si vous prenez l'habitude de déclarer tout avant de l'utiliser, la plupart de vos problèmes vont disparaître dans une grande hâte. Lors de la déclaration de variables, je les initialiser avec une valeur valide tout de suite pour s'assurer qu'aucun d'entre eux ne sont pas définis. J'ai aussi tendance à inclure le code qui vérifie la validité des valeurs de variables globales avant une fonction utilise. C'est une protection supplémentaire contre les erreurs.
Les détails techniques de la façon dont tout cela fonctionne est un peu comme la physique de la façon dont une grenade à main fonctionne lorsque vous jouez avec lui. Mes conseils est de ne pas jouer avec des grenades à main en premier lieu.
Certains de simples déclarations au début du code peut résoudre la plupart la plupart de ces sortes de problèmes, mais certains de nettoyage de code pourrait encore être nécessaire.
Remarque:
J'ai couru un peu d'expériences, et il semble que si vous déclarez toutes vos fonctions de la manière décrite ici, il n'importe pas vraiment ce que l'ordre dans lequel ils sont. Si la fonction utilise la fonction B, la fonction B ne doivent pas être déclarés avant la fonction A.
Donc, déclarer l'ensemble de vos fonctions, votre des variables globales à côté, puis de mettre votre code en dernier. Suivez ces règles de base et vous ne pouvez pas vous tromper. Il peut même être préférable de mettre vos déclarations dans l'en-tête de la page web et de votre code dans le corps afin d'assurer l'application de ces règles.