88 votes

La fonction JavaScript de déclaration et d'évaluation afin

Pourquoi le premier de ces exemples fonctionnent pas, mais tous les autres?

// 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'); }
})();

198voto

slebetman Points 28276

Ce n'est ni la portée, ni est-il un problème la fermeture. Le problème est dans la compréhension entre les déclarations et les expressions.

Code Javascript, car même Netscape première version de javascript et 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 ensuite interprété.

La syntaxe de la fonction de déclaration est:

function name (arguments) {code}

Les 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 des 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:

  1. Rien le droit de l' = ( : sur les littéraux d'objet).
  2. Quoi que ce soit dans des accolades ().
  3. Paramètres à des fonctions (ce qui est déjà couvert par 2).

Les Expressions à la différence des 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 les choses:


// 1
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();

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 de someFunction est pas défini.


// 2
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();

Phase 1: compilation. Le compilateur voit de déclarer une fonction avec le nom someFunction et crée pour cela.

Phase 2: L'interprète voit que vous souhaitez passer someFunction pour le setTimeout. Et il le fait. La valeur actuelle de someFunction est sa fonction compilée déclaration.


// 3
(function() {
setTimeout(function() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();

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 de someFunction est toujours pas défini. Ensuite, il vous voit assigner une fonction à someFunction. À ce stade, la valeur de someFunction 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.


Le 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és 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).

2voto

Javier Points 33134

Javascript est étendue est 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

1voto

matt b Points 73770

Parce qu' someFunction1 n'a pas encore été attribué au moment de l'appel à l' setTimeout() est exécutée.

someFunction3 peut ressembler à un cas similaire, mais puisque vous êtes de passage à une fonction d'habillage someFunction3() de setTimeout() dans ce cas, l'appel à l' someFunction3() n'est pas évalué à plus tard.

1voto

Terry Prothero Points 1

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:

function name (arguments) {code}

É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.

Note Supplémentaire:
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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X