闭包: js一个难点.也是特色. 很多高级应用都要依赖闭包.

要了解闭包,必须先理解js 特殊的 变量作用域.

变量作用域: 全局变量 / 局部变量. js特殊之处: 函数内部可以读取全局变量 函数外部 无法读取函数内的 局部变量.

函数内部声明变量 必须使用 var. 不然的话你声明的是一个全局变量.

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




*closure 闭包: 函数作为返回值*

*高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。*




**如何从外部 读取函数内部的变量. 正常情况是办不到的.**
变通办法:
 在函数内部  再定义一个函数.


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

var result=f1();
result(); // 999

这个代码中: f2函数 在f1 函数内部. f1 中的所有局部变量 对f2 是可见的. f2 中的局部变量 对f1是不可见的. 子对象会一级一级向上寻找所有父对象的变量. 所以父对象的所有变量对子对象都是可见的.反之则不成立.

既然f2 可以读取f1中的变量. 那么只要把f2 作为返回值. 我们就可以在f1 外部读取到f1的内部变量了.

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

闭包用途 它的最大用处有两个,一个是前面提到的可以读取函数内部的变量, 另一个就是让这些变量的值始终保持在内存中。

function f1(){
    var n=999;
      nAdd=function(){n+=1}     // 声明nAdd 函数.
  // 这里注意. nAdd 没有使用 var 使所以nAdd 是个全局变量,
  // nAdd 的值是一个 匿名函数. 这个匿名函数本身也是一个闭包.
  /所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。   
        function f2(){alert(n);}  // 声明 f2 函数. 两种声明方式而已.
    return f2;
  }
  var result=f1();
  result(); // 999
    // 只是执行 f1 函数. 并没有执行里面的 f2 和 nAdd 函数

  nAdd();
  result(); // 1000
    // 只是执行nAdd函数. 这时候并没有执行 f1函数.

这段代码中 
nAdd 函数: 只是定义 不去执行 是不会对nAdd里面的 n 产生影响的.
只有当 倒数第二行 执行 nAdd 函数时候 n 才会 +1;

整段代码中. result(); 执行了两次. 结果分别是999 1000.
可以看出 f1 的局部变量n 一直在内存中, 并没有在f1执行完后 被自动清除.

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。





*闭包注意点:*
*闭包使得函数中的 变量都保存在内存中. 内存消耗很大!!! 不能滥用闭包*
否则会造成网页性能问题, 解决方法: 在退出函数之前, 把不使用的局部变量全部删除.


闭包 会在函数外部 改变函数内部变量的值.使用时候要消息.
不要随便改变函数内部变量的值..






---

我们来实现一个对Array的求和。通常情况下,求和的函数是这样定义的:

function sum(arr) {
return arr.reduce(function (x, y) {
return x + y;
});
}

sum([1, 2, 3, 4, 5]); // 15



但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!
~~~
function lazy\_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}