详解闭包

xiaoxiao2021-02-27  333

什么是闭包?

简单点说,闭包就是函数嵌套函数,其中外部函数可以引用内部函数的参数和变量。

function aaa(a){ var b = 5; function bbb(){ alert(a); alert(b); } } var bbb = aaa(3); bbb();//result : 3 5

垃圾回收机制

垃圾回收机制:在闭包的情况下,参数 a 和 变量 b 是不会被垃圾回收机制回收的,因为内部的闭包还在引用着外部的变量。

//js 中的垃圾回收机制 function aaa(){ var a = 1; } //当这个函数调用完了之后,函数里面的变量就会被垃圾回收机制回收 aaa(); //垃圾回收机制测试 function aaa(){ var a = 5; function bbb(){ alert(a); } return bbb; } //这个时候 aaa 函数已经执行完毕了,这个时候 c //代表的是 bbb 这个函数 var c = aaa(); //这里执行的其实是bbb(); c();// result : 5 //由上述的结果可知:闭包内的变量并不会被垃圾回收机制回收

作用一:模块化代码

闭包可以做到私有成员,私有方法,减少全局变量的污染来达到你想要的效果。

var a = 1; function aaa(){ a++; alert(a); } aaa();//2 aaa();//3 //在这里 a 是全局变量所以我们可以在函数内部使其自增 //如果我们把 a 变成一个局部变量 function aaa(){ var a = 1; a++; alert(a); } aaa();//2 aaa();//2 //在这里 a 只是函数内部的一个局部变量,当我们调用函数的时候不能实现其自增。

如何做到让 a 既是局部变量同时我们在外部调用的时候让 a 又可以累加?这就是我们的闭包可以做到的。

写法一:

function aaa(){ var a = 1; return function (){ a++; alert(a); } } var c = aaa(); c();//2 c();//3 //可以看到当我们在使用闭包的写法的时候,可以做到让 a 既是局 //部变量同时在外部调用函数时,又可以实现其累加

写法二:(改写为函数声明)

//改写为函数声明 (function (){ var a = 1; return function (){ a++; alert(a); } } )()();

也可以像下面这样改写:

var aaa = function (){ var a = 1; return function (){ a++; alert(a); } }(); aaa();//2 aaa();//3 //这就是模块化代码,通过减少全局变量的污染来达到想要的效果

模块化代码模型

var aaa = function(){ //局部变量 var a = 1; //私有方法 function bbb(){ a++; alert(a); } //私有方法 function ccc(){ a++; alert(a); } return { b : bbb, c : ccc } }(); aaa.b();//2 aaa.c();//3

作用二:在循环中直接找到对应元素的索引不需要再加索引

<ul> <li>111</li> <li>222</li> <li>333</li> </ul> window.onload = function(){ var aLi = document.getElementsByTagName('li'); for(var i=0; i<aLi.length; i++){ aLi[i].onclick = function(){ alert(i);//3 //为什么这里会弹出3 因为当循环执行结束的时候,这 //个事件其实还没有执行,只有当我们点的时候,它才会 //执行,但是当我们去点的时候,这个 for 循环已经结 //束了,这个时候 i 已经变成3了,所以不管你点哪一 //个最终弹出来的都是3 } } }

用闭包来解决这个问题:(第一种写法)

window.onload = function(){ var aLi = document.getElementsByTagName('li'); //第一种写法 for(var i=0; i<aLi.length; i++){ (function(i){ aLi[i].onclick = function(){ alert(i); } })(i); } }

用闭包来解决这个问题:(第二种写法)

window.onload = function(){ var aLi = document.getElementsByTagName('li'); 第二种写法 for(var i=0; i<aLi.length; i++){ //当你点击的时候,我这个里面已经执行完毕了,所以这个 i 已经 //驻扎在内部了,所以点击的时候,你调用的 i 是内部的函数已经 //存在内存中的 i了,而不是外面的 i aLi[i].onclick = (function(i){ return function(){ alert(i); } })(i); } }

注意事项:内存泄漏

在 ie 下使用闭包会引发内存泄漏。

引发内存泄漏的条件:当一个变量,这个变量是由获取一个 dom节点,或者是一个宿主对象的时候,他的一个属性,比如说 onclick 去引用一个内部函数,而这个内部函数又去,引用外部的对象,这个时候就会造成内存泄漏。即 ie 下的 js互相引用会造成内存泄漏。

<body> <div id="div1"></div> <script> window.onload = function(){ var oDiv = document.getElementById('div1'); oDiv.onclick = function(){ alert(oDiv.id); } //就是这个简单的程序可能会造成 ie 下的内存泄漏,如果内存泄漏的 //话,当你页面跳转的时候,变量不会释放,一直存在于内存中,使你 //的 cpu 在累加,大大降低了浏览器的性能,只有当你关闭浏览器的 //情况下才能释放内存。 } </script> </body>

解决方法如下:

<body> <div id="div1"></div> <script type="text/javascript"> window.onload = function(){ var oDiv = document.getElementById('div1'); oDiv.onclick = function(){ alert(oDiv.id); } //解决方法: window.onunload = function(){ oDiv.onclick = null; } } </script> </body>

第二种解决方案:

<body> <div id="div1"> </div> <script type="text/javascript"> window.onload = function(){ var oDiv = document.getElementById('div1'); //第二种解决方法:在外部建一个变量引用一下 var id = oDiv.id; oDiv.onclick = function(){ alert(oDiv.id); } //调用完之后还要把这个对象置空 oDiv = null; } </script> </body>
转载请注明原文地址: https://www.6miu.com/read-5672.html

最新回复(0)