Le mécanisme de chaînage de portées en JavaScript peut provoquer certains effets secondaires : une fermeture ne peut obtenir que la dernière valeur de n'importe quelle variable dans la fonction conteneur. Lorsque nous utilisons des fermetures, nous devons faire attention à la valeur de la variable, car c'est là que se produisent souvent les erreurs.
Ci-dessous, nous utilisons un exemple très extrême pour illustrer ce problème. Dans le développement réel, nous n'écrivons généralement pas de code comme celui-ci. Le code de cet exemple est le suivant :
function fn1(){ var arr = new Array(); //变量i保存在fn1作用域中 for(var i = 0; i < 10;i++){ arr[i] = function(){ return i; } } return arr; } var values = fn1(); for(var i = 0; i < values.length;i++){ //此时通过闭包来调用所有的函数,当输出i的时候会到上一级的作用域中查找,此时i的值是10,所以输出的都是10 document.write(values[i]()+"<br>"); }
En exécutant le code ci-dessus, nous nous attendons à ce que 0-9 soit imprimé sur la page, mais 10 10 seront en réalité imprimés. Analysons ce code : une fonction fn1 est créée dans le code d'implémentation, un objet tableau est créé dans la fonction, et une valeur est attribuée au tableau via une boucle for. La boucle est répétée 10 fois, et à chaque fois une fonction anonyme. est rempli dans le tableau et renvoie la valeur, et renvoie enfin un objet tableau. Obtenez ensuite la référence à la fonction fn1, puis affichez les valeurs dans le tableau sur la page via une boucle.
Le modèle de mémoire de chaîne de portée du programme ci-dessus est présenté dans la figure ci-dessous :
Sur la figure, nous pouvons voir qu'à chaque fois dans la fonction fn1 Les boucles généreront une fonction anonyme et auront leurs propres chaînes de portée. Les bits élevés de leurs chaînes de portée pointent vers la portée globale, les bits du milieu pointent vers la portée fn1 externe et les bits faibles pointent vers leur propre portée.
Une fois la fonction fn1 exécutée, la valeur de l'attribut i dans la portée de fn1 est 10. À ce moment, le GC commence à recycler fn1, mais il constate qu'il existe une fonction anonyme pointant vers la portée de fn1, donc la portée de fn1 n'est pas recyclée.
Lorsque la fonction anonyme est exécutée, elle recherche l'attribut i dans son propre espace, mais ne le trouve pas, elle va donc dans sa portée fn1 supérieure pour le trouver. À ce moment, la valeur i dans. la portée fn1 est de 10, donc toutes les fonctions anonymes obtiendront la même valeur i : 10.
La façon de résoudre ce problème est de renvoyer une fonction anonyme dans la fonction anonyme et de sauvegarder la valeur actuelle via une variable. Le code est le suivant :
function fn1(){ var arr = new Array(); for(var i = 0; i < 10;i++){ arr[i] = function(num){ return function(){ return num; } }(i); } return arr; } var values = fn1(); for(var i = 0; i < values.length;i++){ //每一个fs都是在不同的作用域链中,num也是保存在不同的作用域中,所以输出0-9 document.write(values[i]()+"<br>"); }
A ce moment, la valeur de num est stockée dans la portée de chaque fonction anonyme, et la valeur est exactement égale à la valeur d'index de chaque boucle. De cette façon, chaque fois que la fonction anonyme est appelée, elle trouvera l'attribut num dans son propre espace, et les valeurs de ces num sont différentes, en même temps, elle ne cherchera pas l'attribut i dans. la portée de la fonction fn1.
Le code ci-dessus générera la portée de 20 fonctions anonymes. Si le code n'est pas une simple valeur de retour, mais des opérations plus complexes, il occupera beaucoup d'espace mémoire.
Cet objet en fermeture
L'utilisation de cet objet en fermeture entraînera également des problèmes inattendus. L'objet this est lié au moment de l'exécution en fonction de l'environnement d'exécution de la fonction : pour les fonctions globales, cet objet est une fenêtre, et lorsque la fonction est appelée en tant que méthode d'un objet, il s'agit de cet objet. Dans les fonctions anonymes, cet objet pointe généralement vers window. Regardons l'exemple suivant :
var name = "window"; var person = { name : "Leon", age:22, say:function(){ return function(){ return this.name; } } } console.info(person.say()()); //控制台输出:window
Dans le code ci-dessus, lorsque nous appelons la méthode say() de l'objet personne, ce qui est imprimé n'est pas le nom de l'objet personne, mais le nom global "fenêtre". Une fois person.say() terminé, l'appel de fonction est terminé avant la fin de l'appel de fonction, cela pointe vers person, mais lorsque la fonction anonyme est appelée, cela pointe vers window, donc le résultat est "window" .
La façon de résoudre ce problème est d'attribuer cette référence à une variable temporaire dans la méthode say(). Le code est le suivant :
var name = "window"; var person = { name : "Leon", age:22, say:function(){ var that = this; return function(){ return that.name; } } } console.info(person.say()()); //控制台输出:Leon
Ce qui précède est la fermeture JavaScript - les variables dans la fermeture et le contenu de cet objet. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www. php.cn) !