理解javascript闭包和C++闭包

http://www.jb51.net/article/24101.htm js闭包深入浅出
http://segmentfault.com/a/1190000000652891 js闭包实例
http://www.cnblogs.com/Aion/p/3449756.html 关于C++闭包

在js中闭包是一个难点,其他语言例如C++、C#、java等都有闭包的实现。

javascript闭包

js闭包概念

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。
那就是在函数的内部,再定义一个函数。

先来下一个概念:闭包(closure)就是能够读取其他函数内部变量的函数

function f1(){
    n=999;
    function f2()
    {
        alert(n); // 999
    }
}

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。这就是Javascript语言特有的“链式作用域”结构(chain scope),
子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

将上述代码改成

function f1(){
   n=999;
   function f2(){
      alert(n);
   }
   return f2;
    }
var result=f1();
result(); // 999

代码中f2就是闭包,由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

js闭包特性

有以下特性

  • 函数嵌套函数
  • 函数外部可以引用内部的参数和变量
  • 参数和变量不会被垃圾回收机制回收

js闭包的用途

一个是前面提到的可以读取函数内部的变量
另一个就是让这些变量的值始终保持在内存中。

js闭包注意点

由于IE的js对象和DOM对象使用不同的垃圾收集方法,因此闭包在IE中会导致内存泄露问题,也就是无法销毁驻留在内存中的元素

js闭包实例

  function aaa() {  
          var a = 1;  
          return function(){
           alert(a++)
          };  
        }         
        var fun = aaa();  
        fun();// 1 执行后 a++,,然后a还在~  
        fun();// 2   
        fun = null;//a被回收!! 

fun就是aaa里面那个局部函数的闭包,闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗。

 function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  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,可以在函数外部对函数内部的局部变量进行操作。

C++闭包

C++里面的闭包解释不太一样。

闭包是带有上下文的函数。说白了,就是有状态的函数

函数是代码, 状态是一组变量 ,将代码和一组变量捆绑 (bind) , 就形成了闭包。

C++中实现闭包的三种方式

重载 operator()

因为闭包是一个函数+一个状态, 这个状态通过 隐含的 this 指针传入. 所以 闭包必然是一个函数对象. 因为成员变量就是极好的用于保存状态的工具, 因此实现 operator() 运算符重载, 该类的对象就能作为闭包使用. 默认传入的 this 指针提供了访问成员变量的途径.(事实上, lambda 和 bind 的原理都是这个.)

class MyFunctor
{
public:
    MyFunctor(float f) : round(f) {}
    int operator()(float f) { return f + round; }
private:
    float round;
};
float round = 0.5;
MyFunctor f(round);

lambda表达式

float round = 0.5;
auto f = [=](float f) { return f + round; }

C++11里面的lambda就是闭包的实现。

boost::bind/std::bind

int boost_func(float f, float round)
{ return f + round; }
float round = 0.5;
boost::function<int(float)> f = boost::bind(boost_func, _1, round);

closure的状态特指其运行的上下文。 closure将存贮它运行时需要的上下文,从而保证在closure创建时的上下文可以在closure运行时依然有效。

比如round就是closure的上下文。保存上下文的这一特点通常被称作“capture”或者是”bind”。 capture可以自己写,比如MyFuctor f(round); 也可以用boost::bind。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值