一、什么是闭包?
特点:
1 函数嵌套函数
2 内部函数可以引用外部的参数和变量
3 参数和变量不会被垃圾回收机制所回收
举一个简单的闭包的例子,例子中符合闭包的三个特点
function aaa(a){ var b = 5; function bbb(){ alert(a); alert(b); } } aaa();
关于js 中的垃圾回收机制,这里说明一下。请看下面代码,当aaa函数执行完毕之后,aaa中的变量a会被js的垃圾回收机制所回收
function aaa(){ var a = 1; } aaa(); // 改函数执行完毕时候,函数中的变量a会被js的垃圾回收机制所回收
再举一个闭包例子
当aaa函数执行完毕之后,调用c函数仍然可以弹出1,说明了a这个变量没有被垃圾回收
function aaa(){ var a = 1; function bbb(){ alert(a); } return bbb; } var c = aaa(); // 当aaa函数执行完毕之后,调用c函数仍然可以弹出1,说明了a这个变量没有被垃圾回收 c();
二、闭包有什么好处?应用在哪?
2.1 好处:
1 可以使一个变量常驻内存
2 避免全局变量的污染
3 私有成员变量的存在
举个例子,例子中,使用全局变量a实现每次调用aaa函数,变量a++,过多使用全局变量不容易维护(全局变量的污染)。
var a = 1; function aaa(){ a++; alert(a); } aaa(); //2 aaa(); //3 alert(a); // 这里的a是全局变量
下面,使用闭包实现这个例子:
由于a是局部变量,防止了全局变量污染
function aaa(){ var a = 1; return function bbb(){ a++; alert(a); } } var b = aaa(); b(); //2 b(); //3 alert(a); // 由于a是局部变量,外面无法引用,程序报错
使用函数表达式的形式,改造上面例子
关于函数表达式的知识点,可以查看JS函数声明与函数表达式的区别 http://www.cnblogs.com/linhp/p/6085567.html
var aaa = (function (){ var a = 1; return function bbb(){ a++; alert(a); } })();// 这里已经执行了 aaa(); //2 aaa(); //3
私有成员变量的例子:
将表达式中的函数bbb与ccc通过json的方式返回,外部只能调用返回的json中的函数bbb和ccc,而无法访问a这个成员变量。
var aaa = (function (){ var a = 1; function bbb(){ a++; alert(a); } function ccc(){ a++; alert(a); } return {b:bbb,c:ccc} })(); aaa.b(); aaa.c();
2.2 用法:
1 模块化代码
2 在循环中,直接找到对应元素的索引
模块化代码就不举例了,上面的代码都能体现
下面举例(在循环中,直接找到对应元素的索引)
先看下面例子:
<script> window.onload = function (){ var oLi = document.getElementsByTagName("li"); for (var i = 0; i < oLi.length; i++) { oLi[i].onclick = function (){ alert(i); } } } </script> <ul> <li>111111111111</li> <li>222222222222</li> <li>333333333333</li> </ul>
上面例子中,想通过给每一个li添加点击事件,点击每个li,弹出li的索引,而上面例子中,由于for循环已经结束,而onclick事件还没触发,此时i已经等于3了,所以你无论点击哪一个li都无法获取索引,弹出的值都是3
下面,通过闭包的形式,改造,获取索引
window.onload = function (){ var oLi = document.getElementsByTagName("li"); for (var i = 0; i < oLi.length; i++) { (function(i){ oLi[i].onclick = function (){ alert(i); } })(i); //循环过程中,这里已经执行了。参数i永驻内存,所以当你点击li的时候,可以获取得到0,1,2 } }
也可以改造成下面的样子
window.onload = function (){ var oLi = document.getElementsByTagName("li"); for (var i = 0; i < oLi.length; i++) { oLi[i].onclick = (function (i){ return function(){ alert(i) }; })(i); } }
三、闭包需要注意的地方?
3.1 IE下会引发内存泄露
内存泄露会导致浏览器内存占用过高,内存中的变量无法变量,必须关闭浏览器,关闭这个网页也无法清除
window.onload = function(){ var oDiv = document.getElementById("div1"); oDiv.onclick = function(){ alert(oDiv.id); // 由于内部引用了oDiv,导致oDiv无法释放 } }
可以通过onunload事件,将onclick取消,来释放oDiv
window.onload = function(){ var oDiv = document.getElementById("div1"); oDiv.onclick = function(){ alert(oDiv.id); // 由于内部引用了oDiv,导致oDiv无法释放 } window.onunload = function(){ oDiv.onclick = null; } }
或者:
window.onload = function(){ var oDiv = document.getElementById("div1"); var id = oDiv.id; oDiv.onclick = function(){ alert(id); // 由于内部引用了oDiv,导致oDiv无法释放 } oDiv = null; }
来源:https://www.cnblogs.com/linhp/p/6084953.html