一。定义:当内部函数被保存在外部时,会生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏。
<script type="text/javascript">
function a(){
function b(){
var bbb=234;
document.write(aaa);
}
var aaa=123;
return b; //b被抛到了全局范围,抛出的是地址,b不执行
}
var glob = 100;
var demo = a();
demo(); //打印出了网页的123
</script>
页面的效果:
123
这张图很好的诠释了作用域链,也形象的表示了闭包未释放内存,也有利于理解下面将要讲解的闭包的作用。
二。闭包的作用:
1)实现共有变量。例如,函数累加器
<script type="text/javascript">
function a(){
var num = 100;
function b(){
num++;
console.log(num);
}
return b;
}
var demo = a();
demo(); //101
demo(); //102
</script>
AO a { num : 102 }
他的累加形象图可以参考 一 中的手绘图,形象的描述了没有释放a函数的内存,从而导致a函数每次的执行期上下文都被更新保存到b函数的定义阶段。
2)可以做缓存(存储结构)
这个就类似上面的例子了,都是基于他没有释放内存。
3)可以实现封装,属性私有化。
例子,Person(),这是个高级应用的例子,详情参考另外一篇博客。这里不做详细分析。
4)模块化开发,防止污染全局变量。
这个也在下面的博客中,详情参考博客 命名空间。
三。在这里,还是用一个有趣的实例给大家举例一下
请看代码如下:
<script type="text/javascript">
function test(a,b,c,d){
var arr=[];
for(var i = 0;i < 10;i++){
arr[i] = function(){
document.write(i+" ");
}
}
return arr;
}
var myarr = test();
for(var j = 0;j < 10;j++){
myarr[j]();
}
</script>
大家猜一下上面的代码在网页上是什么呈现呢?你可能会猜想 1 2 3 4 5 6 7 8 9 10 是吗?
如果是这样的话,那请你再仔细推理一下,找一下其中的逻辑错误。
好了,让我们看一下页面效果:
是不是有点惊讶呢。惊讶为什么是10个 10 。下面我给大家解释一下:
在这里非常典型的用到了闭包的知识。在第一个for循环中,有一个arr赋值语句。变量声明,声明提升。这个赋值语句是一个函数引用,把一个函数赋值给了一个变量(这是函数表达式)。注意了, = 符号 前面的arr[i] 会改变,而document.write()这个我们之前学过,他直接改变了页面结构,return arr 相当于把输出值直接抛到了函数体的外部,函数会保存在外部,这就直接形成了一个闭包。在 = 赋值语句执行的时候才会考虑这样一个问题: i 是什么。
形成了闭包,就有10个不同的函数,每个函数执行时都会产生一个独一无二的执行期上下文(这个知识点不懂的话,大家可以参考我之前写过的预编译和作用域链两篇文章的开头部分),每个函数相互独立,但是注意他们的函数内容是相同的。
继续读代码,读到第二个for循环大家注意一下。myarr[i](); 这里执行的时候,在这里索取 i ,而此时 i 已经变成了 10.
相同的练习题,工大家练习一下
选A
打印 2 2
打印 2 1