javascript
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
在这段代码中,result()它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。为什么会这样呢?尤其是第二次,为何输出的不是999呢?
nAdd=function(){n+=1}又起到了什么作用呢?
首先要说的是,闭包是functional language里面的核心概念。
当出现高阶嵌套函数的时候,编译器会做
closure convention闭包变换
,核心就是变量不在分配在stack上,而是分配在heap上。这就是为什么f1已经返回,但是n还能被+1的原因。楼主给出的这个程序,实际上就是一个高阶嵌套函数。
1. 因为在函数里面有定义的函数,这是嵌套。pascal也是允许嵌套函数。
2. 高阶的原因是,函数可以所谓参数传递和返回,像我们熟悉的C语言。
但是当高阶和嵌套同时出现,就会造成麻烦,所以pascal和C都只能支持其中的一个。
我来分析一下这个程序的执行流。
1. var result=f1(); 返回了一个函数f2, 因此result为f2。这个高阶函数特性,参考C语言函数指针。
2. result(); 调用f2,显然输出999.
3. nAdd(); 这里需要注意,这个nAdd实际上在定义的时候是一个lambda,是一个匿名函数,功能是n+=1。定义时将这个函数赋值给nAdd。所以在此时,实际上是调用了n+=1.为什么能找到n?因为n在堆里面。
4. result(); 调用f2,显然输出1000.
最后一点,n在堆上如何被销毁,这个工作是垃圾收集器负责。当n不在被任何闭包的env引用的时候,会被回收。