Ce n'est ni un problème de portée ni un problème de fermeture. Le problème est dans la compréhension entre déclarations et expressions.
code JavaScript, car même première version de Netscape de première copie de JavaScript et Microsoft de celui-ci, est traité en deux phases:
Phase 1: compilation - dans cette phase, le code est compilé dans un arbre de syntaxe (et bytecode ou binaire en fonction du moteur).
Phase 2: exécution - le code analysé est ensuite interprété.
La syntaxe de la fonction déclaration est:
function name (arguments) {code}
Les arguments sont bien sûr en option (le code est facultatif aussi bien, mais quel est le point de cela?).
Mais JavaScript vous permet également de créer des fonctions en utilisant les expressions . La syntaxe des expressions de fonction est similaire aux déclarations de fonction, sauf qu'elles sont écrites dans le contexte d'expression. Et les expressions sont:
- Tout à droite d'un signe
=
(ou :
sur les littéraux d'objet).
- Tout entre parenthèses
()
.
- Paramètres des fonctions (ceci est déjà couvert par 2).sont traités dans la phase d'exécution
expressions contrairement __gVirt_NP_NNS_NNPS<__ déclarations plutôt que la phase de compilation. Et à cause de cela, l'ordre des expressions compte.
Donc, pour préciser:
// 1
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();
Phase 1: compilation. Le compilateur voit que la variable someFunction
est définie pour la créer. Par défaut, toutes les variables créées ont la valeur non définie. Notez que le compilateur ne peut pas encore affecter de valeurs à ce stade, car les valeurs peuvent nécessiter que l'interpréteur exécute du code pour renvoyer une valeur à affecter. Et à ce stade, nous n'exécutons pas encore de code.
Phase 2: exécution. L'interpréteur voit que vous voulez passer la variable someFunction
à setTimeout. Et c'est ainsi. Malheureusement, la valeur actuelle de someFunction
n'est pas définie.
// 2
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();
Phase 1: compilation. Le compilateur voit que vous déclarez une fonction avec le nom someFunction et donc il le crée. Phase 2: L'interpréteur voit que vous voulez passer someFunction
à setTimeout. Et c'est ainsi. La valeur actuelle de someFunction
est sa déclaration de fonction compilée.
// 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 la crée. Comme précédemment, sa valeur est indéfinie.
Phase 2: exécution. L'interpréteur passe une fonction anonyme à setTimeout pour être exécuté plus tard. Dans cette fonction, vous voyez que vous utilisez la variable someFunction
pour créer une fermeture de la variable. À ce stade, la valeur de someFunction
est toujours indéfinie. Ensuite, il vous voit attribuer une fonction à someFunction
. À ce stade, la valeur de someFunction
n'est plus indéfinie. 1/100ème de seconde plus tard les déclencheurs setTimeout et la fonction someFunction est appelée. Puisque sa valeur n'est plus indéfinie, cela fonctionne.
Cas n ° 4 est vraiment une autre version de cas 2 avec un peu de cas 3 jeté. Au point someFunction
est passé à SetTimeOut il existe déjà parce qu'elle est déclarée.
précisions supplémentaires:
On peut se demander pourquoi setTimeout(someFunction, 10)
ne crée pas de fermeture entre la copie locale de someFunction et celui passé à setTimeout. La réponse à cela est que les arguments de 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. Ainsi, setTimeout n'obtient pas réellement la variable someFunction qui lui est transmise (ce qui aurait signifié la création d'une fermeture) mais seulement l'objet auquel fait référence someFunction (qui dans ce cas est une fonction).C'est le mécanisme le plus largement utilisé en JavaScript pour casser les fermetures (par exemple dans les boucles).
C'était une très bonne réponse. –
Il s'agit probablement d'un manque de compréhension des fermetures, mais j'ai toujours pensé qu'il s'agissait d'un accès à une portée, et non pas de créer quelque chose entre une portée et une autre. Je pensais aussi que c'était au niveau de la portée, pas au niveau variable. Cela vous dérangerait-il d'en dire un peu plus à ce sujet ou de m'indiquer ce que je peux lire? Encore une fois, bonne réponse, j'aimerais pouvoir voter deux fois. –
Cette réponse me donne envie de voter plusieurs fois pour la même réponse. Vraiment une bonne réponse. Merci – ArtBIT