javascript学习笔记(十三) js闭包介绍(转)

复制代码 代码如下: function f1(){ var n =
999; nAdd = function(){ n += 1; } function f2; } return f2; }
这里的闭包是f1,封闭了一个变量n和一个函数f2。
我们先无视nAdd,尽量保持原貌重写一下这个函数。 复制代码 代码如下: function f1(){ var n = 999;
var f2 = function; }; return f2; } var result = f1;
js中各个变量以function为单元进行封装,当在function内部找不到某一变量时,function会向其所在的上一单元中进行查找,一直查找到顶层的window域。
这时就出现一个疑问:这个查找过程是以函数引用位置为起点还是函数体定义的位置为起点?
在上面这一段代码中,result所在域是window,但是实际的输出结果是f1内部的n值,所以可以得出结论:变量查找的起点是函数体定义的位置。
现在再回过头来看nAdd。如我们所知,没有关键字var定义的变量默认进入window域,所以nAdd实际为window.nAdd。这就等同于如下代码:
复制代码 代码如下: var nAdd; function
f1(){ var n = 999; nAdd = function(){ n += 1; } function f2; } return
function; }; } 那么根据我们对result的分析,nAdd的执行将影响f1中n的值。
所以有: 复制代码 代码如下: function
f1(){ var n = 999; nAdd = function(){ n += 1; } function f2; } return
function; }; } var result = f1; result();
这段代码执行最终的输出结果为1000。 再看这种情况: 复制代码 代码如下: function f1(){ var n = 999;
nAdd = function(){ n += 1; } function f2; } return function; }; } f1;
f1; //复制代码 代码如下: function f1(){ var n = 999; nAdd = function(){
n += 1; } function f2; } return function; }; } var result = f1; f1; //

**在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
六、结语
理解JavaScript的闭包是迈向高级JS程序员的必经之路,理解了其解释和运行机制才能写出更为安全和优雅的代码。

function outerFun()
{
//没有var
a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);

复制代码 代码如下:

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

这段代码有两个特点:
1、函数b嵌套在函数a内部;
2、函数a返回函数b。
引用关系如图:

要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。 Javascript语言…

复制代码 代码如下:

复制代码 代码如下:

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

function outerFun() {
var a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);

**
  简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。

三、闭包内的微观世界

在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。

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

  var name = “The Window”;
  var object = {
    name : “My Object”,
    getNameFunc : function(){
      return function(){
        return this.name;
     };
    }
};
alert(object.getNameFunc()()); //The Window

四、闭包的应用场景
保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)
私有属性和方法在Constructor外是无法被访问的

到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是说b可以访问到a中定义的所有变量和函数。函数b被c引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。

结果为 0,0 真是奇怪,为什么呢?
作用域链是描述一种路径的术语,沿着该路径可以确定变量的值
.当执行a=0时,因为没有使用var关键字,因此赋值操作会沿着作用域链到var a=4;
并改变其值.
如果你对javascript闭包还不是很理解,那么请看下面转载的文章:(转载:)

复制代码 代码如下:

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
}
innerFun()

以上3点是闭包最基本的应用场景,很多经典案例都源于此。
**五、Javascript的垃圾回收机制

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

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

复制代码 代码如下:

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

另一方面,在函数外部自然无法读取函数内的局部变量。

复制代码 代码如下:

复制代码 代码如下:

一、变量的作用域
要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

三、闭包的概念
上一节代码中的f2函数,就是闭包。
各种专业文献上的“闭包”(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
四、闭包的用途
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
怎么来理解这句话呢?请看下面的代码。