Maison >interface Web >js tutoriel >Comprendre les compétences javascript de Closures_Javascript
1. Nous devons d’abord connaître la chaîne de portée variable
Il existe deux types de portées de variables : les variables globales et les variables locales. Les variables qui ne sont définies dans aucune fonction sont des variables globales et les variables définies dans une fonction sont des variables locales. Notez que vous devez utiliser le mot-clé var lors de la définition de variables à l'intérieur d'une fonction. Les variables sans le mot-clé var sont des variables globales.
Chaque morceau de code en JavaScript a une chaîne de portée associée. Cette chaîne de portée est une liste d'objets ou une liste chaînée qui définit les variables dans la « portée » de ce morceau de code. La portée du code de niveau supérieur se compose de variables globales ; la chaîne de portée qui n'inclut pas les fonctions imbriquées a deux objets : l'un est l'objet des paramètres de fonction définis et des variables locales, et l'autre est l'objet variable globale et le ; portée de la fonction imbriquée La chaîne comporte trois objets : paramètres de fonction et variables locales - paramètres de fonctions externes et variables locales - variables globales. Les fonctions peuvent accéder aux objets sur la chaîne de portée, de sorte que les fonctions peuvent accéder aux variables globales, mais pas l'inverse, c'est-à-dire que les variables locales au sein d'une fonction ne sont pas accessibles depuis l'extérieur de la fonction.
var a=1; function wai(){ alert(a); var m=10; n=20; } wai(); //=> 1; 函数内部可以访问全局变量 alert(m); //=> error; 外部访问函数局部变量报错 alert(n); //=> 20; 函数内部定义的变量未使用var关键字,所以是全局变量,外部可以访问
2. Comment lire les variables locales en externe
Parfois, nous devons accéder aux variables locales au sein d'une fonction depuis l'extérieur. Dans ce cas, nous devons utiliser une solution de contournement. Nous utilisons les caractéristiques de la portée des variables JavaScript pour définir des sous-fonctions à l'intérieur de la fonction, et la sous-fonction peut accéder aux variables de la fonction parent
function wai(){ var m=10; function nei(){ alert(m); } return nei; } var f = wai(); nei(); //=> error; nei()函数是一个局部变量,在外部不能访问 f(); //=> 10;
3. Clôture
La fonction nei() dans le code précédent est une fermeture. Comme le montre ce qui précède, une fermeture est une fonction qui peut lire les variables locales à l'intérieur de la fonction. , il peut être considéré comme la fonction à l'intérieur et à l'extérieur de la fonction Ponts qui relient les extérieurs entre eux.
Les fermetures ont deux fonctions :
Tout d'abord, comme mentionné précédemment, vous pouvez lire les variables à l'intérieur de la fonction
Deuxièmement, ces variables locales peuvent être stockées en mémoire pour réaliser le partage de données variables
function wai(){ var m=99; function nei(){ alert(m); m++; } return nei; } var f= wai(); f(); //=> 99; f(); //=> 100; f(); //=> 101;
Dans l'exemple ci-dessus, lorsque la fonction wai() est en cours d'exécution, la variable m est enregistrée dans la mémoire. La valeur de m peut être lue en exécutant f(), mais direct alert(m) ne le peut pas !
Nous pouvons également transmettre des paramètres à la fonction de fermeture. Comme le montre l'exemple suivant, une fonction anonyme est définie et une fonction de fermeture est renvoyée. La fonction ajoute les paramètres passés à la variable locale i dans la fonction anonyme, et Make. j'incrémente;
var wai=(function(){ var i=0; return function(num){ num+=i; alert(num); i++; } })(); wai(1);//1 wai(2);//3 wai(3);//5
Pour comprendre plus en profondeur les fermetures, regardons l'exemple suivant :
Maintenant, je veux définir une fonction qui renvoie un tableau, et chaque élément du tableau est une fonction, et chaque fonction affichera la valeur d'index correspondante
On pourrait écrire comme ça
function box(){ var arr=[]; for(i=0;i<5;i++){ arr[i]=function(){return i;} } return arr; } var a=box(); alert(a); //=>包含五个函数体的数组 alert(a[0]()); //=> 5; alert(a[1]()); //=> 5;
Le code ci-dessus révèle que toutes les fenêtres contextuelles sont 5, et non 0,1,2,3,4 comme nous nous y attendions, car i est également une variable locale qui existe en mémoire lorsque nous exécutons a[0. ]() À ce moment-là, la valeur de i est déjà 5 et la valeur de i continue d'augmenter pendant tout le processus d'exécution de la fonction box().
Solution : Mise en place des fermetures
function box(){ var arr=[]; for(var i=0;i<5;i++){ arr[i]=(function(num){ return function(){return num;} })(i); } return arr; } var arr=box(); for(var i=0;i<5;i++){ alert(arr[i]());//0,1,2,3,4 }
4. Choses à noter lors de l'utilisation des fermetures
1) Étant donné que les fermetures entraîneront le stockage des variables de la fonction en mémoire, ce qui consomme beaucoup de mémoire, les fermetures ne peuvent pas être abusées, sinon cela entraînerait des problèmes de performances sur la page Web et pourrait entraîner des fuites de mémoire dans C'est à dire. La solution consiste à supprimer toutes les variables locales inutilisées avant de quitter la fonction.
2) La fermeture modifiera la valeur de la variable à l'intérieur de la fonction parent en dehors de la fonction parent. Par conséquent, si vous utilisez la fonction parent comme objet, la fermeture comme méthode publique et les variables internes comme valeur privée, vous devez faire attention à ne pas modifier les valeurs des variables de la fonction parent.
5. Voici quelques questions sur les fermetures
Si vous pouvez comprendre les résultats du code suivant, vous devez comprendre le mécanisme de fonctionnement des fermetures.
Code Js
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; //=>嵌套函数的this为全局变量或undefined,不会继承父函数的this }; } }; alert(object.getNameFunc()()); //The Window
La raison pour laquelle la sortie ci-dessus est "La fenêtre" est que ceci dans la fonction imbriquée n'hérite pas de la fonction parent this, et sa valeur est une variable globale ou non définie (sous ECMAScript5), donc ce qui est renvoyé est le nom variable de l'objet global. Si vous souhaitez qu'il renvoie l'attribut name de l'objet, le code est le suivant :
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var cur=this; return function(){ return cur.name; }; } }; alert(object.getNameFunc()()); //=》My Object
Le code ci-dessus attribue celui de l'objet fonction parent à la variable cur, et sa fonction imbriquée peut accéder à ses propriétés via la variable cur
-------------------------------------------------------------- --- ----------------------------------------------- --- -----
Exemple de fermeture JavaScript
function outerFun() { var a=0; function innerFun() { a++; alert(a); } } innerFun(); //=>error
Le code ci-dessus est erroné. La portée de innerFun() est à l'intérieur de externalFun(), et il est faux de l'appeler en dehors de externalFun().
est remplacé par ce qui suit, ce qui est une fermeture :
Code Js
function outerFun() { var a=0; function innerFun() { a++; alert(a); } return innerFun; //注意这里 } var obj=outerFun(); obj(); //结果为1 obj(); //结果为2 var obj2=outerFun(); obj2(); //结果为1 obj2(); //结果为2
什么是闭包:
当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.
--------------------------------------------------------------------------------------------------------
再来看一个例子
Js代码
function outerFun() { var a =0; alert(a); } var a=4; outerFun(); //=> 0 alert(a); //=> 4
结果是 0,4 . 因为在函数内部使用了var关键字 维护a的作用域在outFun()内部.
再看下面的代码:
Js代码
function outerFun() { //没有var a =0; alert(a); } var a=4; outerFun(); //=> 0 alert(a); //=> 0
结果为 0,0 真是奇怪,为什么呢?
作用域链是描述一种路径的术语,沿着该路径可以确定变量的值 .当执行a=0时,因为没有使用var关键字,因此赋值操作会沿着作用域链到var a=4; 并改变其值.