js闭包之我见

对于闭包,我自己有一点简单的理解

作用域链

js中函数查找变量的顺序是由内到外的,先查找函数内部的变量,再查找父函数中的变量,以此类推。

内存回收机制

一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.

闭包

如果这个函数内部又嵌套了另一个函数,而这个函数是有可能在外部被调用到的.并且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.如果在外部函数返回后,又直接调用了内部函数,那么内部函数就无法读取到他所需要的外部函数中变量的值了.所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.
下面来看一下一个例子
java代码:

1
2
3
4
5
6
7
8
window.onload=function(){
var li=document.getElementsByTagName('li');
for(var i=1;i<li.length;i++){
li[i].onclick=functon(){
alert(i);
}
}
}

html代码:

1
2
3
4
5
6
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>

运行起来,大家可能很惊讶,全都弹框输出5;因为onclick绑定的函数都引用了同一个变量i,循环执行完后i=5;最后点击按钮时,调用函数,找到变量i=5,自然输出是5。
我们可以改进一下改吗如下:

1
2
3
4
5
6
7
8
9
10
window.onload = function () {
var li = document.getElementsByTagName('li');
for (var i = 1; i < li.length; i++) {
li[i].onclick = (function (j) {
return function () {
alert(j);
}
})(i);
}
}

如上面的代码所示,我们用一个匿名函数,传入i然后立即执行,并且返回需要绑定到onclick事件的函数。这样返回的函数都访问到的是匿名函数传入的i的值,即j的值。这里我们就用到了闭包的特性,因为onclick事件绑定了function(){alert(j)},所以虽然匿名函数已经执行完并返回了函数,但是局部变量j,仍然还可能被点击事件绑定的函数,还被保存着。当点击事件发生时便执行相应的函数,得到不同的结果。

分享到 评论