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:
- Rien le droit de l'
=
( :
sur les littéraux d'objet).
- Quoi que ce soit dans des accolades
()
.
- 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).