JavaScript闭包

闭包其实就是利用了函数作用域和匿名函数的知识,当函数A执行结束时,一部分变量变量被B引用,被引用的变量不能释放,形成了所谓的闭包。这里有篇很好的文章,可以参考一下。
下面看一个小例子:
<script language="javascript" type="text/javascript">
function show(){
    var n=3;
    setTimeout(function(){alert("first:"+n);},3000); //3秒后显示first:3
    alert("second:"+n); //显示second:3
}
show();
function show2(){alert("第一个函数执行结束");}
show2();
</script>

运行上面的函数后,首先alert显示"second:3",然后显示"第一个函数执行结束",3秒后显示“first:3”。

仔细看一下,函数show执行结束的时候,变量n应该被释放了,内存里也就不存在了,怎么过了3秒还能显示出"first:3"呢?闭包恰恰就在此产生了,当函数show执行结束的时候,想要释放内存里的n,但发现变量n还在被一个匿名函数引用,要在3秒后调用,根据JavaScript闭包原理,内存里的n被保留了下来,于是在三秒以后仍然可以调用n。
下面看几种写法的区别:

function show2(content){
  alert(content);  //3秒后alert显示"test"
}
function show(content,delay_time){
    setTimeout("show2('"+content+"')",delay_time);
}
show("test",3000);
仔细看一下上面这种写法不是闭包,只是普通的函数调用而已。
function show(content,delay_time){
    setTimeout(function(){alert(content)},delay_time); //3秒后alert显示"test"
}
show("test",3000);

这种写法就是闭包,虽然结果是一样的,但原理不一样。
function show(content){
    function show2(){alert(content);}
    return show2;
}
var newshow=show("test");
setTimeout(newshow,3000);  //3秒后alert显示"test"

上面这种写法也是闭包,虽然结果都是一样的,但原理却不一样。这里面看到了函数也可以当作对象也传递,函数show执行后return show2,把函数show2赋值给newshow,然后3秒后,调用newshow对象,执行函数show2。
仔细比较上面3种写法,如果能悟出一些道理就好,闭包有些时候的确难理解。
稍复杂一点的例子:
<script language="javascript" type="text/javascript">
var show=null;
(function(){
  var n=1;
  var show2=function(){
      alert(n++);
  }
  show=show2;
})();

show();  //显示1
show();  //显示2
show();  //显示3
</script>

上面代码中,又一次用了函数作为对象传递,n是匿名函数里的局部变量,外部是访问不到的。show是一个全局变量,应该访问不了变量n,但在函数show执行前,首先把函数匿名函数内部show2赋值给show,当后面函数show运行的时候,会调用show2的代码,而show2是可以访问n的,故结果显示为1、2、3。

CSS代码:

ul{ width:600px; margin:0px auto;}
ul li{ margin:1px 0px; }
HTML代码:
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>
JavaScript代码:
<script language="javascript" type="text/javascript">
var li=document.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
   li[i].onclick=function(){alert(i);}
}
</script>

运行后,不论点击哪一个li,都是alert提示“4”。这就是一个需要注意的地方:闭包允许内层函数引用父函数中的变量,但是该变量是最终值。闭包引用的变量i,是循环结束后的值,其实这是一个很常见的问题。
比较常见的就是给li[i]添加属性值,比如li[i].n=i;还有就是用闭包方法解决,这个函数本身就是闭包,所谓用闭包来解决闭包的问题。代码如下:

<script language="javascript" type="text/javascript">
var li=document.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
   (function(index){
   li[index].onclick=function(){alert(index);}
   })(i); 
}
</script>

 

posted @ 2016-11-10 14:45  行动派  阅读(131)  评论(0编辑  收藏  举报