一、闭包的概念
闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。
二、闭包的作用
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
三、使用闭包的好处
- 希望一个变量长期驻扎在内存中
- 避免全局变量的污染
- 私有成员的存在
四、闭包的缺点:
常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
五、闭包的原理:
先看一段代码:1
2
3
4
5
6
7
8
9
10
11var x = 20;
function foo() {
alert(x); // 自由变量"x" == 20
}
// 为foo闭包
fooClosure = {
call: foo // 引用到function
lexicalEnvironment: {x: 20} // 搜索上下文的上下文
};
上述例子中,“fooClosure”部分是伪代码。对应的,在ECMAScript中,“foo”函数已经有了一个内部属性——创建该函数上下文的作用域链。“lexical”通常是省略的。上述例子中是为了强调在闭包创建的同时,上下文的数据就会保存起来。当下次调用该函数的时候,自由变量就可以在保存的(闭包)上下文中找到了。
对于要实现将局部变量在上下文销毁后仍然保存下来,基于栈的实现显然是不适用的(因为与基于栈的结构相矛盾)。因此在这种情况下,上层作用域的闭包数据是通过 动态分配内存的方式来实现的(基于“堆”的实现)。
六、使用闭包
全局变量的累加
1
2
3
4
5
6
7
8
9
10
11
12<script>
function outer(){
var x=10;
return function(){ //函数嵌套函数
x++;
alert(x);
}
}
var y = outer(); //外部函数赋给变量y;
y(); //y函数调用一次,结果为11,相当于outer()();
y(); //y函数调用第二次,结果为12,实现了累加
</script>模块化代码,减少全局变量的污染
1
2
3
4
5
6
7
8
9
10
11<script>
var abc = (function(){ //abc为外部匿名函数的返回值
var a = 1;
return function(){
a++;
alert(a);
}
})();
abc(); //2 ;调用一次abc函数,其实是调用里面内部函数的返回值
abc(); //3
</script>私有成员的存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<script>
var aaa = (function(){
var a = 1;
function bbb(){
a++;
alert(a);
}
function ccc(){
a++;
alert(a);
}
return {
b:bbb, //json结构
c:ccc
}
})();
aaa.b(); //2
aaa.c() //3
</script>在循环中直接找到对应元素的索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<script>
window.onload = function(){
var aLi = document.getElementsByTagName('li');
for (var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){ //当点击时for循环已经结束
alert(i);
};
}
}
</script>
<body>
<ul>
<li>123</li>
<li>456</li>
<li>789</li>
<li>010</li>
</ul>
</body>
- 使用闭包改写上面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<script>
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);
}
};
</script>
<body>
<ul>
<li>123</li>
<li>456</li>
<li>789</li>
</ul>
</body>
七、特别提醒
(function(){})(i) 中也存在闭包的原因: function(){}是一个函数,(function(){})(i)中也是个函数,函数中嵌套函数,且变量i相对于function(){}是一个函数是上下文变量,会记住i的值。