请选择 进入手机版 | 继续访问电脑版
设为首页收藏本站

就爱编程论坛

 找回密码
 注册

人人连接登陆

无需注册,直接登录

用新浪微博连接

一步搞定

QQ登录

只需一步,快速开始

查看: 1696|回复: 0

闭包 Javascript的垃圾回收机制 匿名函数 [复制链接]

Rank: 9Rank: 9Rank: 9

  • TA的每日心情
    无聊
    2018-5-6 00:05:45
  • 签到天数: 383 天

    [LV.9]以坛为家II

    论坛先锋 学习至圣 荣誉成员 论坛元老 活跃之星 终极领袖

    发表于 2012-6-4 16:31:49 |显示全部楼层
    function addNum(a,b){
      function add(n1,n2){  return n1+n2;   }
      return add(a,b);
    }

    闭包,指某种程序语言中的代码块允许一级函数存在并且在一级函数中所定义的自由变量能不被释放,直到一级函数被释放前,一级函数外也能应用这些未释放的自由变量。
    闭包,其实就是指程序语言中能让代码调用已运行的函数中所定义的局部变量。闭包,就是封闭了外部函数作用域中变量的内部函数。但是,如果外部函数不返回这个内部函数,闭包的特性无法显现。如果外部函数返回这个内部函数,那么返回的内部函数就成了名副其实的闭包。此时,闭包封闭的外部变量就是自由变量,而由于该自由变量存在,外部函数即便返回,其占用的内存也得不到释放
    闭包的方式:
    a.自运行模式
    (function(params_declare){//params_declare 参数声明
    //使用params_declare do something
      })(parms_value);//parms_value要求是参数值
    匿名函数就是没有实际名字的函数,也是被调用的哦(如上红色的括号,表明调用和参数)!(function(x,y){  return  x+y;})(2,3);
    b.方法对象模式
    function Fun(parms){
       var  innerParams;//内部参数
    function innerFun(){//内部函数要求没有参数
    //利用fun的参数和innerParmas参数 do something
         //注意:innerFun对innerParams的变动,会影响每一个Fun的实例化的对象
    }
    return  innerFun;//必须没有括号
    }
    自运行模式示例
    当用户先后按住键盘的ctrl+enter时,弹出消息
    (function(mess){
      var  clickCount=0;//记录时间触发次数的变量
    var  preCode="";//记录前一个键盘的Code的便来那个,用于判断是不是ctrl键
    document.body.onkeydown =  function(){
      if(preCode=="17" && event.keyCode=="13"){
        clickCount++;//自增
    alert(mess+",次数:"+clickCount);//第一次提示消息:"触发事件,次数:1",第二次提示消息:"触发事件,次数:2"
       }else{
       preCode=event.keyCode;//记录前一个键盘的Code
       }
    }})("触发事件");

    当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
    function a(){
          var  i=0;
          function b(){ alert(++i);}
          return b;  //函数a将其内部函数b返回
    }
    var c = a();//变量c指向了函数b
        c();   //执行c()后就会弹出一个窗口显示i的值(第一次为1)
        c();c();c();  //我们多执行几次看看
    闭包有什么作用?
    在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC(如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收)不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。

    闭包的微观世界,Javascript中的变量查找机制
      1、当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义a时a所在的“环境”,如果a是一个全局函数,则scope  chain中只有window对象。
      2、当函数a执行的时候,a会进入相应的执行环境(excution context)。
      3、在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope  chain。即a.scope=a的作用域链。
      4、然后执行环境会创建一个活动对象(call  object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。
      5、在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。
      6、最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。
      到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是说b可以访问到a中定义的所有变量和函数。函数b被c引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。
      当函数b执行的时候亦会像以上步骤一样。因此,执行时b的作用域链包含了3个对象:b的活动对象、a的活动对象和window对象.
    当在函数b中访问一个变量的时候,搜索顺序是先搜索自身的活动对象,如果存在则返回,如果不存在将继续搜索函数a的活动对象,依  次查找,直到找到为止。如果整个作用域链上都无法找到,则返回undefined。如果函数b存在prototype原型对象,则在查找完自身的活动对象  后先查找自身的原型对象,再继续查找
    闭包的应用场景
      1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
      2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
    [img=http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=fRUcHhYWGAQ9GxIFEBwUEVMeEhA]http://rescdn.qqmail.com/zh_CN/htmledition/images/function/qm_open/ico_mailme_02.png[/img]

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册 人人连接登陆

    晴云孤魂's Blog|就爱编程搜帖|手机版|Archiver|就爱编程论坛     

    GMT+8, 2018-6-20 11:49 , Processed in 0.086008 second(s), 24 queries .

    Powered by Discuz! X2

    © 2001-2011 Comsenz Inc.

    回顶部