javascript 闭包详解
看了一下网上闭包的概念及文章,对于这个问题,自己做一个梳理吧。
问:闭包是什么?
答:闭包是指在JavaScript中,内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
这个是我自身第一次碰到闭包的问题
<!DOCTYPEHTML> <html> <head> <metacharset="utf-8"/> <title>闭包循环问题</title> <styletype="text/css"> p{background:#ccc;width:300px;height:100px;} </style> </head> <body> <pid="p0">段落0</p> <pid="p1">段落1</p> <pid="p2">段落2</p> <pid="p3">段落3</p> <pid="p4">段落4</p> <scripttype="text/javascript"> for(vari=0;i<5;i++){ document.getElementById("p"+i).onclick=function(){ alert(i);//访问了父函数的变量i,闭包 }; }; </script> </body> </html>
如果你以前没这么用过的话,估计也会认为单击某个段落就会弹出这个段落相应的编号0,1,2,3,4。但实际上是都是弹出5;
对于这个问题网上已经有很多讨论的博客了,他们给出了很多方法去实现弹出对应的编号。
解决方法1:将变量i保存在对应的段落的某个属性上
varpAry=document.getElementsByTagName("p"); for(vari=0;i<5;i++){ pAry[i].no=i; pAry[i].onclick=function(){ alert(this.no); } };
解决方法2:加一层闭包,i以函数参数形式传递给内层函数
varpAry=document.getElementsByTagName("p"); for(vari=0;i<5;i++){ pAry[i].no=i; pAry[i].onclick=function(){ alert(this.no); } };
对于这个产生的闭包问题,网上的说法是“变量i是以指针或者变量地址方式保存在函数中”;好吧,都和指针扯上关系了。。。。那就再探索一下吧。
探索1,返回的都是10而不是而是
(functiontest(){ vartemp=10; for(vari=0;i<5;i++){ document.getElementById("p"+i).onclick=function(){ alert(temp);//访问了父函数的变量temp,闭包 } }; temp=20; })();
探索2,返回一次10,接下去返回的都是20
(functiontest(){ vartemp=10; for(vari=0;i<5;i++){ document.getElementById("p"+i).onclick=function(){ alert(temp);//访问了父函数的变量i,闭包 } if(i===1){ alert(temp); } }; temp=20; })();
由探索的1、2,可以得出结论:函数内部访问了与函数同级的变量,那么该变量是常驻内存的。访问该变量实质上是访问的是变量的地址;
接着,又看了一篇关于“JS闭包中的this对象”的文章,继续来讨论一下,this这个问题吧。
//js闭包this对象1 varname='TheWindow'; varobject={ name:'MyObject', getNameFunc1:function(){ //returnthis.name; console.log(this);//object returnfunction(){//闭包,访问的便是全局变量的了,this指windows console.log(this);//windows returnthis.name;//TheWindow } }, getNameFunc2:function(){ returnthis.name;//访问的是object }, aa:function(){ alert(22); } }; alert(object.getNameFunc1()());//弹出“TheWindow”
问:那么为什么匿名函数没有取得其包含作用域的this对象呢?
答:每个函数在被调用时都会自动获取两个特殊变量:this和arguments。内部函数在搜索这两个变量时,指挥搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。
不过通过下面的代码可以做到这一点(直接访问外部函数中的变量):
//js闭包this对象2 varname='TheWindow'; varobject={ name:'MyObject', getNameFunc:function(){ varthat=this; console.log(this);//输出的是object returnfunction(){ console.log(this);//输出的仍然是Windows returnthat.name; }; } }; alert(object.getNameFunc()());//弹出“MyObject”
不同之处在于把this对象赋给了一个that变量,即使在函数返回之后,that也仍然引用这object,所以会返回object。
写了那么多闭包的东西,那也顺便再说一下闭包有神马用处吧;不然,一直捣乱那闭包可真是一个不好的家伙呢。
看这样一典型的闭包的例子:
functionA(){ vara=1; functionB(){ returna; }; returnB; }; varC=A();//C取得A的子作用域B的访问接口 console.log(C());//1C能访问到B的父级作用域中的变量a
只要其他作用域能取到子作用域的访问接口,那么其他作用域就有方法访问该子作用域父级作用域的变量了。这样的话,如果以后需要访问某个函数里面的值得时候,就大大的有用咯。
这些上面的很多代码其实也都是网上找的,我也只是把自己理解的,看的过程总结一下吧。