##实现基本的闭包
####返回一个函数
// 注释: 定义fn接收函数只执行后返回的对象(函数或者包含函数的对象)
// a为要控制的数据变量,方法fn1,fn2控制这个局部变量a
var fn = (function (){
var a;
a = 1;
return function () {
a += 2;
alert(a);
}
})()
// 测试代码
fn(); // 执行a+=2;,输出结果为3
fn();// 执行a+=2;,输出结果为5
fn = null; // 垃圾回收,释放内存
####返回一个包含方法的对象
// 注释: 定义fn接收函数只执行后返回的对象(函数或者包含函数的对象)
// a为要控制的数据变量,方法fn1,fn2控制这个局部变量a
var fn = (function (){
var a,fn1,fn2; // 局部私有变量和方法
a = 1;
fn1 = function (){
a++;
return a;
}
fn2 = function (){
a--;
return a;
}
return {
fn1:fn1,
fn2:fn2
}
})()
// 测试代码
console.log(fn.fn1()); // 执行a++,输出结果为2
console.log(fn.fn2());// 执行a--,输出结果为1
console.log(fn.fn1());// 执行a++,输出结果为2
fn = null; // 垃圾回收
##闭包解决循环内嵌异步函数(事件驱动的函数或定时器函数) ####1.错误的方法
<!DOCTYPE html>
<html xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<title>闭包解决循环问题</title>
<style>
li {
height: 30px;
width: 100px;
text-align: center;
line-height: 30px;
background-color: pink;
margin-top: 10px;
}
</style>
</head>
<body>
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
<li>列表4</li>
</ul>
<script>
var Lis = document.getElementsByTagName('li');
for (var i = 0; i < Lis.length; i++) {
// 依次给每个li标签注册事件
Lis[i].onclick = function () {
alert(i); // 点击列表1,输出4;点击列表2,输出的也是4;点击3,4结果亦同;
};
}
</script>
</body>
</html>
####2.运用闭包解决上面问题,只需要改写script标签里的JavaScript代码
var Lis = document.getElementsByTagName('li');
for (var i = 0; i < Lis.length; i++) {
Lis[i].onclick = (function (i) {
return function (){
alert(i); // 点击列表0,输出0;点击列表1,输出1;成功输出正确的值
// 用闭包包裹变量 i 后,并将全局i通过传参的方式传入,i 变成了函数内的一个局部私有变量,
// return出的这个事件执行函数里访问不再是全局的 i,而是这个局部变量 i ,此时就能正确输出;
}
})(i);
Lis[i] = null;
}
####3.当然,闭包并不是解决这个问题的最佳方法,因为闭包存在内存泄露问题尽量不要使用,下面介绍一种通过给DOM节点设置自定义属性方式解决这个问题
var Lis = document.getElementsByTagName('li');
for (var i = 0; i < Lis.length; i++) {
Lis[i].index = i;
Lis[i].onclick = function () {
alert(this.index); // 这里的this指向,调用他的当前DOM节点,也就是当前的 li 标签
};
}
####4.最好的方法自然是ES规范里的东西,利用ES6新标签let来解决上面问题
var Lis = document.getElementsByTagName('li');
// 很简单只需要把var 改成let就行了,这是i就认为是一个局部块级作用域
// 这种方法虽然简单,但是ES6浏览器还没有被普遍支持,所以我们一般用Babel对它进行转译后才能使用。
for ( let i = 0; i < Lis.length; i++) {
Lis[i].onclick = function () {
alert(i);
};
}
// 温馨提示:关于let的详细用法请参考阮一峰的ES6入门,http://es6.ruanyifeng.com/