Lecture des contenus
Qu'est-ce qu'une fermeture ?
Caractéristiques des fermetures
Fonction des fermetures :
Exemples de code de fermetures
Notes
Résumé
Fermeture est un concept important en JavaScript, et c'est également une technologie fréquemment utilisée dans le travail quotidien. Faisons-en un petit résumé
Qu'est-ce qu'une fermeture ?
Déclaration officielle :
Une fermeture fait référence à une fonction qui a accès à une variable dans la portée d'une autre fonction. Une façon courante de créer une fermeture est de créer une autre fonction à l'intérieur d'une fonction et d'accéder aux variables locales de cette fonction via une autre fonction
Ce qui suit est une fermeture simple :
function A(){ var text="hello world"; function B(){ console.log(text); } return B; } var c=A(); c(); // hello world
Selon le sens littéral : la fonction B a le droit d'accéder à la variable (texte) dans le cadre de la fonction A, et d'accéder au texte de la variable locale de cette fonction via une autre fonction C. La fonction B forme donc une fermeture. On peut aussi dire que C est une fermeture, car C exécute réellement la fonction B.
Il convient de noter qu'il n'y aura aucune réaction si A(); Parce que return B n'est exécuté que s'il s'agit de return B();
Caractéristiques de la fermeture
La fermeture a trois caractéristiques :
1. Fonction fonction imbriquée
2. Les paramètres et variables externes peuvent être référencés à l'intérieur de la fonction
3. Les paramètres et variables ne seront pas recyclés par le mécanisme de collecte des ordures
Expliquez le point 3, pourquoi les paramètres de fermetures et Will les variables ne sont-elles pas recyclées par le mécanisme de récupération de place ?
Tout d'abord, comprenons le principe du garbage collection en javascript :
(1) En javascript, si un objet n'est plus référencé, alors l'objet sera GC (garbage collection). ) Recyclage ;
(2) Si deux objets font référence l'un à l'autre et ne sont plus référencés par un tiers, alors les deux objets qui font référence l'un à l'autre seront également recyclés.
Dans l'exemple de code ci-dessus, A est la fonction parent de B, et B est affecté à une variable globale C (le cycle de vie de la variable globale ne se terminera que lorsque le navigateur déchargera la page), ce qui provoque B doit toujours être en mémoire, et l'existence de B dépend de A, donc A est toujours en mémoire et ne sera pas recyclé par le mécanisme de récupération de place (garbage collection) une fois l'appel terminé.
Le rôle de la fermeture :
En fait, le rôle de la fermeture est également déterminé par les caractéristiques de la fermeture. Selon les caractéristiques de la fermeture ci-dessus, le rôle de la fermeture est le suivant : <🎜. >
1. Vous pouvez lire les variables à l'intérieur de la fonction au lieu de définir des variables globales pour éviter de polluer l'environnement 2. Gardez les valeurs de ces variables en mémoire. Exemples de code de fermeturesCe qui suit présente principalement plusieurs fermetures courantes et les analyse : demo1 Accumulation de variables locales.function countFn(){ var count=1; return function(){ //函数嵌套函数 count++; console.log(count); } } var y = countFn(); //外部函数赋给变量y; y(); //2 //y函数调用一次,结果为2,相当于countFn()() y(); //3 //y函数调用第二次,结果为3,因为上一次调用的count还保存在内存中,没有被销毁,所以实现了累加 y=null; //垃圾回收,释放内存 y(); // y is not a function
for (var i = 0; i < 10; i++) { var a = function(){ console.log(i) } a() //依次为0--9 }
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); //10次10 }, 1000); }
for(var i=0;i<10;i++){ var a=function(e){ return function(){ console.log(e); //依次输入0--9 } } setTimeout(a(i),0); }
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); //依次打印出0-9 }, 0); })(i); }
<ul id="test"> <li>第一个</li> <li>第二个</li> <li>第三个</li> <li>第四个</li> </ul> var nodes = document.getElementsByTagName("li"); for(i = 0,len=nodes.length;i<len;i++){ nodes[i].onclick = function(){ alert(i); //值全是4 }; }
由于绑定的回调函数是一个匿名函数,所以上面的代码中, 这个匿名函数是一个闭包,携带的作用域为外层作用域(也就是for里面的作用域),当事件触发的时候,作用域中的变量已经随着循环走到最后了。
还有一点就是,事件是需要触发的,而绝大多数情况下,触发的时候循环已经结束了,所以循环相关的变量就是最后一次的取值。
要实现点击li,alert出li的索引值,需要将上面的代码进行以下的修改:
<ul id="test"> <li>第一个</li> <li>第二个</li> <li>第三个</li> <li>第四个</li> </ul> var nodes=document.getElementsByTagName("li"); for(var i=0;i<nodes.length;i++){ (function(e){ nodes[i].onclick=function(){ alert(e); }; })(i) }
解决思路: 增加若干个对应的闭包域空间(这里采用的是匿名函数),专门用来存储原先需要引用的内容(下标)。
当立即执行函数执行的时候,e 值不会被销毁,因为它的里面有个匿名函数(也可以说是因为闭包的存在,所以变量不会被销毁)。执行后,e 值 与全局变量 i 的联系就切断了,
也就是说,执行的时候,传进的 i 是多少,立即执行函数的 e 就是多少,但是 e 值不会消失,因为匿名函数的存在。
也可以用下面的解法,原理是一样的:
<ul id="test"> <li>第一个</li> <li>第二个</li> <li>第三个</li> <li>第四个</li> </ul> var nodes=document.getElementsByTagName('li'); for(var i = 0; i<nodes.length;i++){ (function(){ var temp = i; nodes[i].onclick = function () { alert(temp); } })(); }
注意事项
1、造成内存泄露
由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,所以只有在绝对必要时再考虑使用闭包。
2、在闭包中使用this也可能会导致一些问题。
其实我们的目的是想alert出object里面的name
var name="The Window"; var object={ name:"My Object", getNameFunc:function(){ return function(){ return this.name; } } } alert(object.getNameFunc()()); // The Window
因为在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window。
每个函数在被调用时,都会自动取的两个特殊变量:this和 arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止。也就是说,里面的return function只会搜索
到全局的this就停止继续搜索了。因为它永远不可能直接访问外部函数中的这两个变量。
稍作修改,把外部作用域中的this对象保存在一个闭包能够访问的变量里。这样就可以让闭包访问该对象了。
var name="The Window"; var object={ name:"My Object", getNameFunc:function(){ var that=this; return function(){ return that.name; } } } alert(object.getNameFunc()()); // My Object
我们把this对象赋值给了that变量。定义了闭包之后闭包也可以访问这个变量。因此,即使在函数返回之后,that也仍引用这object,所以调用object.getNameFunc()()就返回 “My Object”了。
总结
当在函数内部定义了其他函数,就创建了闭包。闭包有权访问包含函数内部的所有变量。
闭包的作用域包含着它自己的作用域、包含函数的作用域和全局作用域。
当函数返回一个闭包时,这个函数的作用域会一直在内存中保存到闭包不存在为止。
使用闭包必须维护额外的作用域,所有过度使用它们可能会占用大量的内存
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持PHP中文网!
更多理解javascript中的闭包相关文章请关注PHP中文网!