JavaScript 关于闭包的思考 总结

来源:互联网 发布:it难学吗 编辑:程序博客网 时间:2024/06/06 01:15
最近在看Javascript,起初认为闭包仅仅就是函数访问外部的变量这么简单,但是后来接触到一个简单的递归函数的时候,才开始了对闭包的思考。闭包可以说是一种底层机制的上层体现(我是这么认为的)。是先有了底层的垃圾回收及作用于链、引用等机制,才进而产生了“闭包”。

 

  • 闭包是指有权访问另一个函数作用于中的变量的函数【引自《Javascript高级编程第二版》P144】。定义很简单~但也太浅显。定义中没有提及闭包的潜在功能和其意义,所以还需要我们继续探索,闭包究竟可以为我们做什么。

 

作用域链

  • 在创建一个函数的时候,会预先为其创建一个包含全局变量对象的作用域链,保存在一个特殊内部属性Scope中
  • 当某个函数第一次被调用时会创建一个执行环境及相应作用域链,并赋值给Scope
  • 使用this、arguments和其他参数的值初始化函数的活动对象

    有了上面三步,一个函数的作用域链便组合完毕。外部函数的活动对象是始终处于内部活动对象之后的!所以其作用域链中包含两个变量对象:1本地活动对象;2全局变量对象。(只引用,不包含)

 

一般函数执行完毕后,局部活动对象就被销毁,,内存中仅仅保存全局作用于。但闭包的情况不同!

[c-sharp] view plaincopyprint?
  1. function kkk() {  
  2.   var a = 1;  
  3.   return function(){alert(a++)};  
  4. }         
  5. var fun = kkk();  
  6. fun();// 1 执行后 a++,,然后a还在~  
  7. fun();// 2   
  8. fun = null;//a被回收!!  

    上例形象的说明了,函数kkk在执行完之后,其局部活动对象中a并没有被回收,因为在一个匿名函数的作用域链中被引用,而且此匿名函数被外部的fun引用。所以,仅仅是kkk的执行环境作用域链被销毁了,而活动对象仍然在内存中,直到引用者--匿名函数被销毁。

 

    !闭包,会携带作用域,占用内存!

 

闭包变量

  • 闭包会取其执行时状态的外部变量值!而不是定义时状态~[个人理解]。(定义时并不执行,因为只绑定变量,不绑定变量值。所以在运行时绑定变量值的时候,或许值就早已不是你定义时想要的值了。)看下面的例子~:
[c-sharp] view plaincopyprint?
  1. function TTT(){  
  2.     var r = [];  
  3.     for ( var i=0; i<10; i++ ){  
  4.         r[i] = function(){  
  5.             return i;  
  6.         }  
  7.     }  
  8.     return r;  
  9. }  
  10. var m = TTT();  
  11. for( var i=0; i<m.length; i++ ){  
  12.     alert( m[i]() );//弹出的都是 10,而不是1、2、3...10  
  13. }  

    上例在运行的时候,到第二个for循环中才去分别调用匿名函数,去返回i,但是那个时候的i已经早早变成10了,因为还存在引用所以没被销毁(闭包)。不是我们想要的提示1、2、3之类的。这是闭包容易出现的一个问题。怎么解决呢?呵呵当然是想办法取消那个运行时才返回的i了,我们可以让它提前返回:

[c-sharp] view plaincopyprint?
  1. for ( var i=0; i<10; i++ ){  
  2.     r[i] = function(m){  
  3.     return function(){  
  4.        return m;  
  5.     };  
  6.   }(i);//顺便执行了,将返回值赋值给r[i]。这其中包含了两次闭包我认为。。一次是封闭了i值,另一次是将i值赋给m以后,闭包m的值。此时与i不再有关系,这样一来,就可以顺利输出1、2、3...  
  7. }  

     注释中仅代表我个人的理解。


原创粉丝点击