JavaScript的闭包

闭包(closure)是javascript语言的一个难点,也是特色之一,很多高级应用(如Jquery)都要依赖闭包实现。要理解闭包,首先必须理解JavaScript特殊的变量作用域。变量的作用域包括全局变量和局部变量,JavaScript语言的特殊之处就在于函数内部可以直接读取全局变量,如下例:

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

在函数外部无法读取函数内的局部变量,如:

function(){
  var n='test';
}
alert(n);//error

注意函数内部声明变量时一定要用var命令;否则实际上声明了一个全局变量,如:

function f1(){
  n = 'test';
}
f1();
alert(n);//test

处于种种原因,有时候需要得到函数内的局部变量。但是必须通过变通方法实现。即在函数的内部再定义一个函数,如:

function f1(){
  var n = 'test';
  function f2(){
    alert(n); //test
  }
}

在上面的代码中,函数f2被包含在函数f1内部。这时f1内部的所有局部变量对f2都是可见的,但是f2内部的局部变量对f1不可见。这就是JavaScript语言所特有的“链式作用域”结构(chain scope),子对象会一级一级地向上查找所有父对象的变量。所以父对象的所有变量对子对象都是可见的,反之则不成立。 既然f2可以读取f1中的局部变量,那么只需要把f2作为返回值,即可在f1外部读取其内部变量,如:

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

上面的f2函数就是闭包。

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

闭包最大的用处有两个,一是前面提到的读取函数内部的变量;二是让这些变量始终保存在内存中,实现数据共享。

var cnt = (function(){
   var i = 0;
   return function(){
    alert(i);
    i++;
  }
})();
cnt();//显示0
cnt();//显示1
cnt();//显示2

第一次调用[cnt()]后开始执行无名函数,执行后变量i的值将保存在内存中;第二次调用[cnt()]时将使用内存中保存的i值,因此值为1;

var cnt = (function (num){
    return function(){
    alert(num);
    num++;
  }
})(5);
cnt();//显示5
cnt();//显示6
cnt();//显示7

另外,还可以在调用时指定参数值,如:

var cnt = (function (){
   var i=0;
   return function(num){
   num++;
   alert(num);
   num++;
 }
})();
cnt(5);//显示5
cnt(6);//显示6
cnt(7);//显示7
 
var cnt = (function(){
   var i = 1;
   return {
   counter:function(){
   i++;
   this.getValue();
},
getValue:function(){
   return alert(i);
 }
}
})();

cnt.counter();//显示1
 cnt.getValue();//显示1
 cnt.counter();//显示2 

标签

发表评论