JavaScript闭包

闭包:

  指有权访问另一个函数作用域中的变量的函数。
      创建闭包的常见方式,就是在一个函数内部创建另一个函数。

 1   function createComparisonFunction(propertyName){
 2             return function(obj1,obj2){//匿名函数
 3                 var value1 = obj1[propertyName];
 4                 var value2 = obj2[propertyName];
 5                 if(value1<value2){
 6                     return -1;
 7                 }else if(value1>value2){
 8                     return 1;
 9                 }else{
10                     return 0;
11                 }
12             };
13         }    

作用域链:

  当某个函数第一次被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋值给一个特殊的内部属性。然后,使用this、arguments和其他命名参数的值来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象始终处于第三位,。。。直至作为作用域链终点的全局执行环境。

 1   function compare(value1,value2){
 2             if(value1<value2){
 3                 return -1;
 4             }else if(value1>value2){
 5                 return 1;
 6             }else{
 7                 return 0;
 8             }
 9         }
10         
11  var result = compare(5,10);

  第一次调用compare()时,会创建一个包含this,arguments,value1和value2的活动对象。全局执行环境的变量对象(包括this,result和compare)在compare()执行环境的作用域链中处于第二位。

  一般来说,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域。但是,闭包的情况又有所不同。

  在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。在外部函数中定义的匿名函数会将外部函数的活动对象添加到它[指匿名函数]的作用域链中)

1 var compare = createComparisonFunction('name');
2 var result = compare({name:'Nicholas'},{name:'Greg'});

  当匿名函数从createComparisonFunction()中被返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。这样,匿名函数就可以访问在createComparisonFunction()中定义的所有变量。createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数仍然在引用这个活动对象。

  就是说,当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中;直到匿名函数被销毁后,createComparisonFunction()的活动对象才会被销毁。例如,

1   var compare = createComparisonFunction('name');
2    var result = compare({name:'Nicholas'},{name:'Greg'});
3    compare = null;//解除对匿名函数的引用,以便释放内存。

this对象:

  this对象是在运行时基于函数的执行环境绑定的--在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。

 1     var name="the window";
 2        var object = {
 3            name:"My Object",
 4             getNameFunc:function(){
 5                 return function(){
 6                     return this.name;
 7                 };
 8             }
 9         };
10         alert(object.getNameFunc()());//the window(非严格模式下)

  object.getNameFunc()返回一个函数,object.getNameFunc()()调用返回的函数,调用对象默认为window对象。
      把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

 1       var name="the window";
 2         var object = {
 3             name:"My Object",
 4             getNameFunc:function(){
 5                 var that = this;
 6                 return function(){
 7                     return that.name;
 8                 };
 9             }
10         };
11         alert(object.getNameFunc()());//My Object    

  定义闭包之后,闭包可以访问that变量,即使外部函数返回之后,that仍然引用这object,所以object.getNameFunc()()返回的是My Object.
        
      特殊情况,

 1     var name="the window";
 2         var object = {
 3             name:"My Object",
 4             getName:function(){
 5                 return this.name;
 6             }            
 7         };
 8         object.getName();//'My Object'
 9         (object.getName)();//'My Object',this的值不变 object.getName = (object.getName)
10         (object.getName=object.getName)();//'the window',非严格模式下.赋值表达式的值是函数本身,this的值不能得到维持

内存泄露:

  如果闭包的作用域链中保存着一个html元素,那么就意味着该元素将无法被销毁。

1     function assignHandler(){
2             var element = document.getElementById("someElement");
3             element.onclick = function(){//闭包函数
4                 alert(element.id);//循环引用,只要匿名函数存在,element的引用书至少是1,它所占用的内存就永远不会被回收。
5             };            
6         }    

修改,

1     function assignHandler(){
2             var element = document.getElementById("someElement");
3             var id = element.id;
4             element.onclick = function(){//闭包函数
5                 alert(id);//消除循环引用,但element仍然被间接引用着
6             };            
7             element = null;//接触对element的引用,回收其占用的内存
8         }
posted @ 2015-04-13 15:51  Youngly  阅读(164)  评论(0编辑  收藏  举报