Fork me on GitHub

谈谈闭包

什么是闭包,如何理解

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

先看个案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
(function (){
var liArr=document.getElementsByTagName('li');
for(var i=0;i<liArr.length;i++){
liArr[i].onclick=function (){
console.log(i)
}
}
})()
</script>

以上代码想输出被点击li的索引号,但结果并非如此,每次输出都是4。

原因在于匿名函数没有变量 i,所以它必须向上查找,在全局环境中找到了 i。

当for循环运行后,全局变量中的 i 变成了4。此时当你点击文字的时候,会调用其绑定的函数,而该函数运行的时候,发现自己没有 i,就会取得全局环境中的 i。

  • 解决办法1

将var更改为let,不知道的点击查看let关键字,干嘛用的?

  • 解决办法2–采用闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for(var i=0;i<dom.length;i++){
dom[i].onclick=function(i){
return function(){
console.log(i);
};
}(i);
}
//当然也可以这样写
for(i = 0;i<nodes.length;i+= 1){
nodes[i].onclick = (function(i){
return function() {
console.log(i);
} //不用闭包的话,值每次都是4
})(i);
}
  • 来,看看有没有理解
1
2
3
4
5
6
7
8
 for(var i=0;i<dom.length;i++){
dom[i].onclick=function(t){
return function(){
console.log(t); //1
console.log(i); //3
};
}(i);
}

闭包的特性

  • 函数内再嵌套函数
  • 内部函数可以引用外层的参数和变量
  • 参数和变量不会被垃圾回收机制回收
1
2
3
4
5
6
7
8
9
10
11
12
function fn() {
// Local variable that ends up within closure
var num = 666;
var sayAlert = function() {
alert(num);
}
num++;
return sayAlert;
}
var sayAlert = fn();
sayAlert(); //执行结果应该弹出的667

执行fn后,内部变量会存在,而闭包内部函数的内部变量不会存在使得Javascript的垃圾收机制GC不会收回fn所占用的资源因为fn的内部函数的执行需要依赖fn中的变量,这是对闭包作用的非常直白的描述。

据说帅的人都赏给博主几块钱零花钱。