首页 > 语言 > JavaScript > 正文

javascript 闭包详解

2024-05-06 16:22:41
字体:
来源:转载
供稿:网友

闭包:是指有权访问另外一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另外一个函数。在javascript中没有块级作用域,一般为了给某个函数申明一些只有该函数才能使用的局部变量时,我们就会用到闭包,我们来详细探讨下

看了一下网上闭包的概念及文章,对于这个问题,自己做一个梳理吧。

问:闭包是什么?

答:闭包是指在 JavaScript 中,内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

这个是我自身第一次碰到闭包的问题

 

 
  1. <!DOCTYPE HTML> 
  2. <html> 
  3. <head> 
  4. <meta charset="utf-8"/> 
  5. <title>闭包循环问题</title> 
  6. <style type="text/css"
  7. p {background:#ccc; width: 300px; height: 100px;} 
  8. </style> 
  9. </head>  
  10. <body>  
  11. <p id="p0">段落0</p>  
  12. <p id="p1">段落1</p>  
  13. <p id="p2">段落2</p>  
  14. <p id="p3">段落3</p>  
  15. <p id="p4">段落4</p>  
  16. <script type="text/javascript"
  17. forvar i=0; i<5; i++ ) {  
  18. document.getElementById("p"+i).onclick=function() {  
  19. alert(i); //访问了父函数的变量i, 闭包  
  20. }; 
  21. }; 
  22. </script>  
  23. </body>  
  24. </html> 

如果你以前没这么用过的话,估计也会认为单击某个段落就会弹出这个段落相应的编号0,1,2,3,4。但实际上是都是弹出5;

对于这个问题网上已经有很多讨论的博客了,他们给出了很多方法去实现弹出对应的编号。

解决方法1:将变量i保存在对应的段落的某个属性上

 

 
  1. var pAry = document.getElementsByTagName("p");  
  2. forvar i=0; i< 5; i++ ) {  
  3. pAry[i].no = i;  
  4. pAry[i].onclick = function() {  
  5. alert(this.no);  
  6. }  
  7. }; 

解决方法2:加一层闭包,i 以函数参数形式传递给内层函数

 

 
  1. var pAry = document.getElementsByTagName("p");  
  2. forvar i=0; i< 5; i++ ) {  
  3. pAry[i].no = i;  
  4. pAry[i].onclick = function() {  
  5. alert(this.no);  
  6. }  
  7. }; 

对于这个产生的闭包问题,网上的说法是“变量i是以指针或者变量地址方式保存在函数中”;好吧,都和指针扯上关系了。。。。那就再探索一下吧。

探索1,返回的都是10而不是而是

 

 
  1. (function test() {  
  2. var temp =10;  
  3. for(var i=0; i< 5; i++ ){  
  4. document.getElementById("p"+i).onclick=function() {  
  5. alert(temp); //访问了父函数的变量temp, 闭包  
  6. }; 
  7. temp=20; 
  8. })(); 

探索2,返回一次10,接下去返回的都是20

 

 
  1. (function test() {  
  2. var temp =10;  
  3. forvar i=0; i< 5; i++ ) {  
  4. document.getElementById("p"+i).onclick=function() {  
  5. alert(temp); //访问了父函数的变量i, 闭包  
  6. if(i===1){ 
  7. alert(temp); 
  8. }; 
  9. temp=20; 
  10. })(); 

由探索的1、2,可以得出结论:函数内部访问了与函数同级的变量,那么该变量是常驻内存的。访问该变量实质上是访问的是变量的地址;

接着,又看了一篇关于“JS闭包中的this对象”的文章,继续来讨论一下,this这个问题吧。

 

 
  1. // js闭包this对象1 
  2. var name = 'The Window'
  3. var object = { 
  4. name : 'My Object'
  5. getNameFunc1 : function(){ 
  6. // return this.name; 
  7. console.log(this);//object 
  8. return function(){//闭包,访问的便是全局变量的了,this指windows 
  9. console.log(this);//windows 
  10. return this.name; //The Window 
  11. }, 
  12. getNameFunc2 : function(){ 
  13. return this.name;//访问的是object 
  14. }, 
  15. aa:function(){ 
  16. alert(22); 
  17. }; 
  18. alert(object.getNameFunc1()());//弹出“The Window” 

问: 那么为什么匿名函数没有取得其包含作用域的this对象呢?

答:每个函数在被调用时都会自动获取两个特殊变量:this 和 arguments。 内部函数在搜索这两个变量时,指挥搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。

不过通过下面的代码可以做到这一点(直接访问外部函数中的变量):

 

 
  1. // js闭包this对象2 
  2. var name = 'The Window'
  3. var object = { 
  4. name : 'My Object'
  5. getNameFunc : function(){ 
  6. var that = this
  7. console.log(this);//输出的是object 
  8. return function(){ 
  9. console.log(this);//输出的仍然是Windows 
  10. return that.name; 
  11. }; 
  12. }; 
  13. alert(object.getNameFunc()());//弹出“My Object” 

不同之处在于把this对象赋给了一个that变量,即使在函数返回之后,that也仍然引用这object,所以会返回object。

写了那么多闭包的东西,那也顺便再说一下闭包有神马用处吧;不然,一直捣乱那闭包可真是一个不好的家伙呢。

看这样一典型的闭包的例子:

 

 
  1. function A(){ 
  2. var a=1; 
  3. function B(){ 
  4. return a; 
  5. };  
  6. return B; 
  7. }; 
  8.  
  9. var C=A();//C取得A的子作用域B的访问接口 
  10. console.log(C());//1 C能访问到B的父级作用域中的变量a  

只要其他作用域能取到子作用域的访问接口,那么其他作用域就有方法访问该子作用域父级作用域的变量了。这样的话,如果以后需要访问某个函数里面的值得时候,就大大的有用咯。

这些上面的很多代码其实也都是网上找的,我也只是把自己理解的,看的过程总结一下吧。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选