打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Javascript和Java中闭包的理解

一。Javascript中闭包:

1.变量的作用域

  要理解闭包,首先必须理解Javascript特殊的变量作用域。
  变量的作用域无非就是两种:全局变量和局部变量。
  
  Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 
[javascript] view plain copy
  1. var n=999;  
  2. function f1(){  
  3.   alert(n);  
  4. }  
  5.  f1(); // 999  

  另一方面,在函数外部自然无法读取函数内的局部变量。 
[javascript] view plain copy
  1. function f1(){  
  2.   var n=999;  
  3. }  
  4.  alert(n); // error  

  这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量! 
[javascript] view plain copy
  1. function f1(){  
  2.   n=999;  
  3. }  
  4.  f1();  
  5.  alert(n); // 999  

2.如何从外部读取局部变量

  出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。
  那就是在函数的内部,再定义一个函数。
[javascript] view plain copy
  1. function f1(){  
  2.   n=999;  
  3.   function f2(){  
  4.     alert(n); // 999  
  5.   }  

  既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!
[javascript] view plain copy
  1.  function f1(){  
  2.    n=999;  
  3.    function f2(){  
  4.      alert(n);  
  5.   }  
  6.   return f2;  
  7. }  
  8. var result=f1();  
  9. result(); // 999  

3.闭包的概念

  上面的f2函数,就是闭包。闭包其实就是定义在一个函数内部的函数(因为是子函数所以能够读取所在父函数的内部变量)。
  在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

4.闭包的用途

  1.可以读取函数内部的变量.
  2.让这些变量(闭包引用的变量)的值始终保持在内存中。
[javascript] view plain copy
  1.  function f1(){  
  2.    var n=999;  
  3.    nAdd=function(){n+=1}  
  4.    function f2(){  
  5.      alert(n);  
  6.    }  
  7.    return f2;  
  8. }  
  9. var result=f1();  
  10. result(); // 999  
  11. nAdd();  
  12. result(); // 1000  
        在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
        为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
        这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个

       匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。


5.使用闭包的注意点

  1.由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包

  2.闭包会在父函数外部,改变父函数内部变量的值。


6.闭包的应用场景

  1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
  2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
 

二。Java中的闭包

1.java中闭包的定义

  定义:闭包能够将一个方法作为一个变量去存储,这个方法有能力去访问所在类的自由变量。

  Java 语言本身还没有正式支持闭包,但它却允许模拟闭包(内部类+接口)。可以使用匿名的内部类来实现闭包。

  如何让这个普通对象能够访问所在类的自由变量?内部类。内部类能够访问外部类的所有属性及方法。

  隐藏具体实现是内部类的作用之一,如何保证隐藏具体实现的同时还能将闭包传递到外部使用?让内部类实现通用接口,然后将内部类对象向上转型为接口类型。

2.代码简单实现:

  1.     public final static String name = "纯牛奶";// 名称  
  2.   
  3.   
  4.     private static int num = 16;// 数量  
  5.   
  6.   
  7.     public Milk() {  
  8.         System.out.println(name + ":16/每箱");  
  9.     }  
  10.   
  11.   
  12.     /** 
  13.      * 闭包 
  14.      *  
  15.      * @return 返回一个喝牛奶的动作 
  16.      */  
  17.     public Active HaveMeals() {  
  18.         return new Active() {  
  19.             public void drink() {  
  20.                 if (num == 0) {  
  21.                     System.out.println("木有了,都被你丫喝完了.");  
  22.                     return;  
  23.                 }  
  24.                 num--;  
  25.                 System.out.println("喝掉一瓶牛奶");  
  26.             }  
  27.         };  
  28.     }  
  29.   
  30.   
  31.     /** 
  32.      * 获取剩余数量 
  33.      */  
  34.     public void currentNum() {  
  35.         System.out.println(name + "剩余:" + num);  
  36.     }  
  37. }  
  38.   
  39.   
  40. /** 
  41.  * 通用接口 
  42.  */  
  43. interface Active {  
  44.     void drink();  
  45. }    
  46.   
  47. //闭包的使用  
  48. public class Person {     
  49.     public static void main(String[] args) {    
  50.         //买一箱牛奶    
  51.         Milk m = new Milk();   
  52.         Active haveMeals = m.HaveMeals();  
  53.         //没事喝一瓶    
  54.         haveMeals.drink();    
  55.         //有事喝一瓶    
  56.         haveMeals.drink();   
  57.         //看看还剩多少?    
  58.         m.currentNum();    
  59.     }     
  60. }    

4.总结: 

   1.实际项目中没怎么用过闭包,因此不能对他的好坏进行评论。 
   2.建议合理的使用闭包,不完全不使用,也不能滥用。 
   3.特别注意:闭包会导致资源不被回收,如上例,在main方法中将m设为null,使用haveMeals继续调用drink方法仍然会喝掉一瓶牛奶,说明Milk对象并没有被释放掉。

  
        
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
javascript深入理解js闭包
学习Javascript(Closure)
前端基本知识:JS的闭包理解
JavaScript 之 作用域
Javascript学习笔记十二则
深入理解JavaScript作用域和作用域链
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服