Je regarde ES2015 pratiquer récemment, il y a un dicton qui dit
Il n'y a pas de portée au niveau du bloc en javascript
Vous ne comprenez peut-être pas ce problème, jetons un coup d'œil à un exemple d'abord
var a = [] pour (var i = 0; i <10; i ++) {a [i] = fonction () {console.log (i); }} a [6] ();Je pense que beaucoup de gens pensent que le résultat de cette question est de 6, mais malheureusement, la réponse est de 10. Essayez autre chose. A [7] (), A [8] () et A [8] () ont tous 10 !!
Puisque JS enveloppe souvent les variables primitives en objets correspondants lors du traitement, par exemple, pour var str = "Hello World"; str.slice (1).
Le véritable processus de JS est probablement var str = "Hello World"; nouvelle chaîne (str) .slice (1). Un tel processus peut causer des problèmes à comprendre le problème.
Afin d'expliquer ce problème ici, j'appartiens au type de nombre dans le type primitif, je le déclare explicitement comme le type de nombre. Étant donné que le processus d'attribution du type de base est de réappliquer la mémoire et de modifier la direction de la variable, nous utilisons également le processus d'objet Re-New Number pour simuler ce processus. Le code modifié est le suivant:
var a = [] var i = nouveau nombre (0); pour (; i <10; i = nouveau nombre (i + 1)) {a [i] = fonction () {console.log (i.ToString ()); }} a [6] (); // 10a [7] (); // 10a [8] (); // 10a [9] (); // 10a [9] (); // 10Jetons un coup d'œil aux adresses de mémoire relatives de ces variables en combinaison avec un programme.
(function () {var id = 0; function generateId () {return id ++;}; object.prototype.id = function () {var newid = generateId (); this.id = function () {return newId;}; return newid;};}) (); var a = [] var i = new nombre (0); console.log (i.id (); nouveau numéro (i + 1), i.id ()) {a [i] = fonction () {console.log (i.id ()); console.log (i.ToString ()); }} a [6] (); // 10 10a [7] (); // 10 10a [8] (); // 10 10a [9] (); // 10 10Console.log (i.id ()) // 10Ici, nous avons en effet simulé tout l'effet "affectation" de notre I, et l'adresse relative de I est passée de 0 à 10 (à la fin, elle doit être ajoutée une fois avant de pouvoir sauter de la boucle pour la boucle).
En regardant l'adresse relative de I, nous avons trouvé un problème: lorsque la fonction correspondant à un [x] (x: 0 ~ 9) est exécutée, l'adresse relative de I référencée est 10. Pourquoi?
Ici, nous impliquerons le problème de portée au niveau du bloc. Ici, nous citons un passage de Ruan Yifeng dans l'introduction à ES6:
ES5 n'a que la portée et la portée globales de la fonction, mais pas de portée au niveau du bloc.
ES5 est la version la plus utilisée de JS. Cette phrase indique qu'en JavaScript, il n'y a pas de portée de bloc. Il n'y a que la portée globale et la portée au niveau du bloc.
Comment comprendre? Par exemple
pour (var i = 0; i <10; i ++) {console.log (i);} console.log (i); // 10Console.log (window.i); // 10Intuitivement, nous pensons que la boucle FOR est un bloc de code et doit appartenir à une portée au niveau du bloc. Cependant, non seulement peut sortir normalement de 0 à 9, mais il peut également sortir 10 en externe dans la boucle FOR. En même temps, nous avons constaté que bien que nous ayons défini i sur la boucle pour, il semble que je m'accroche à l'objet de fenêtre global (s'il s'agit de l'environnement d'exécution de Nodejs, il s'accrochera à l'objet global)
Par conséquent, des blocs comme pour les boucles en JavaScript n'auront pas pour effet d'une portée au niveau du bloc. La définition des variables dans les blocs de code tels que pour les boucles n'est pas différente de la définition directe des variables dans la portée actuelle.
Mais nous pouvons isoler la portée à travers les fonctions:
(function () {for (var i = 0; i <10; i ++) {console.log (i);} console.log (i);}) () console.log (i); //// i n'est pas définiEn même temps, si Console.log (Window.i); est exécuté, le résultat non défini sera obtenu. Ici, nous utilisons une fonction d'exécution immédiate pour former une portée. Il joue un rôle similaire à un bloc de code. Après cette portée de fonction, la variable je ne peux plus accéder. Cependant, je suis accessible à tout moment dans la portée de la fonction.
Revenez à la question précédente, puis nous le comprendrons en combinaison avec uniquement la portée globale et la portée au niveau du bloc en JavaScript. Dans la boucle FOR, le I défini doit être défini dans la portée actuelle, c'est-à-dire la portée de la fenêtre. Dans le corps de la boucle, nous attribuons une fonction à un [i]. Lorsque nous exécutons cette fonction, la situation est la suivante:
Je n'existe pas dans la fonction, nous suivons donc la chaîne de portée pour trouver i. Le i que nous sortions en ce moment est ceci i. Puisque je saute de la dernière +1 de la boucle, je deviens 10, donc le résultat de sortie est toujours 10. Mais ce dont nous avons vraiment besoin n'est pas le dernier I, mais je dans le processus intermédiaire. Si nous voulons résoudre ce problème, nous devons mettre de côté la variable I (parce que la dernière je deviens inévitablement 10). Nous devons laisser la fonction correspondant à un [0] se référer à la valeur 0, et laisser la fonction correspondant à un [1] se référer à la valeur 1. Comme indiqué sur la figure ci-dessous:
Revenez à notre code précédent.
La flèche sur la figure montre que nous pouvons accéder à I (0 ~ 9). Ici, parce que la boucle FOR ne forme pas une portée au niveau du bloc en soi, nous accédons à la boucle pour la boucle pour la chaîne de portée.
Ici, nous enroulons notre code avec une fonction d'exécution immédiate, qui peut former une portée, et nous transmettons la valeur I pour elle. Ce qui suit:
var a = [] var i = nouveau nombre (0); console.log (i.id ()); // 0for (; i <10; i = nouveau numéro (i + 1), i.id ()) {(function (i) {a [i] = function () {console.log (i.id ()); console.log (i.tostring ());}})) (i); // 6 6a [7] (); // 7 7a [8] (); // 8 8a [9] (); // 9 9Console.log (i.id ()); // 10}Étant donné que cette fonction d'exécution immédiate fait référence à la valeur numérique 0 ~ 9, lorsque nous exécutons la fonction a [i], nous trouverons d'abord la portée de la fonction d'exécution immédiate le long de la chaîne de portée. La fonction d'exécution immédiate maintient la référence numérique de 0 ~ 9, et nous pouvons correctement publier la valeur de I dans la fonction a [i]. Grâce au résultat d'exécution, nous pouvons voir que non seulement le résultat d'exécution est correct, mais que l'adresse mémoire relative de la valeur que nous référentes est également correcte. Ensuite, nous modifions l'objet numéro qui a été à l'origine explicitement déclaré pour les tests. Comme suit:
var a = []; for (var i = 0; i <10; i ++) {(function (i) {a [i] = function () {console.log (i);}}) (i);}Enfin, jetons un coup d'œil à la syntaxe ES6 recommandée en utilisant LET au lieu de VAR et compilant et générant du code ES5 via Baable:
// Code es6 var a = [] pour (Soit i = 0; i <10; i ++) {a [i] = function () {console.log (i); }} a [6] (); // Babel a compilé et généré le code ES5 "utiliser strict"; var a = []; var _loop = function _loop (i) {a [i] = function () {console.log (i); };}; pour (var i = 0; i <10; i ++) {_loop (i);} a [6] ();Voyons si notre solution est très similaire à la solution ES6. Ici, notre fonction d'exécution immédiate est équivalente à l'exécution de la fonction _loop et _loop (i) dans le code ES5 généré.