`

理解闭包的概念

阅读更多
最近在网上查阅了不少Javascript闭包(closure)相关的资料,写的大多是非常的学术和专业。对于初学者来说别说理解闭包了,就连文字叙述都很难看懂。撰写此文的目的就是用最通俗的文字揭开Javascript闭包的真实面目。
  一、什么是闭包?
  “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
  相信很少有人能直接看懂这句话,因为他描述的太学术。我想用如何在Javascript中创建一个闭包来告诉你什么是闭包,因为跳过闭包的创建过程直接理解闭包的定义是非常困难的。看下面这段代码:
    function a(){
      var i=0;
      function b(){
        alert(++i);
      }
      return b;
    }
    var c = a();
    c();
  这段代码有两个特点:
  1、函数b嵌套在函数a内部;
  2、函数a返回函数b。
  这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:
  当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
  我猜想你一定还是不理解闭包,因为你不知道闭包有什么作用,下面让我们继续探索。
  二、闭包有什么作用?
  简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。
在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。
  那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。(关于Javascript的垃圾回收机制将在后面详细介绍)
  三、闭包内的微观世界
  如 果要更加深入的了解闭包以及函数a和嵌套函数b的关系,我们需要引入另外几个概念:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。
  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原型对象,则在查找完自身的活动对象后先查找自身的原型对象,再继续查找。这就是Javascript中的变量查找机制。
  四、闭包的应用场景
  1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
  2、在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
  以上两点是闭包最基本的应用场景,很多经典案例都源于此。
  五、Javascript的垃圾回收机制
  在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
转载自 : http://blog.csdn.net/hitman9099/archive/2009/01/28/3854171.aspx
分享到:
评论

相关推荐

    关系概念、传递闭包概念及warshall算法c++程序

    在初学离散数学关系概念、传递闭包概念及warshall算法时,总感觉理论缺乏实例,难以理解,本资源收集了一篇短文,讲清了概念,我结合实例编了c++程序,觉得清晰多了,供大家参考

    understandingClosures:通过解释闭包所依赖的基本概念的一系列脚本来理解闭包

    了解闭包通过解释闭包所依赖的基本概念的一系列脚本来理解闭包主题目录包含 10 个脚本,涵盖了闭包功能所必需的每个主题,逐渐构建到对闭包的理解: 主题 01 - 输入 Javascript 话题 02 - Javascript 中的函数话题 ...

    JS中的闭包理解。。。。。。。。

    这就是“闭包”的概念。 • 每当外部封闭函数执行的时候就产生了闭包,也就是说闭包的创建并不一定需要内部函数返回。 • JavaScript中闭包作用域是词法作用域,即它在代码写好之后就被静态决定了它的作用域。

    javascript中闭包概念与用法深入理解

    主要介绍了javascript中闭包概念与用法,结合实例形式深入分析了javascript中闭包的概念、使用方法与相关注意事项,需要的朋友可以参考下

    [深入理解JS闭包]帮助你快速学习js的闭包,简单高效的文档资源

    帮助你快速学习js的闭包,简单高效的文档资源! 一、变量的作用域 二、如何从外部读取局部变量? 三、闭包的概念 四、闭包的用途 五、使用闭包的注意点 六、思考题 JavaScript闭包例子

    JavaScript核心(对象、原型、继承、上下文、闭包、this).pdf

    面向对象概念(对象封装,各种继承,闭包原理,this作用域等)介绍清晰易懂

    【JavaScript源代码】详细聊聊浏览器是如何看闭包的.docx

    今天打算换个角度来理解闭包,从内存分配与回收的角度阐述,希望能帮助你真正消化掉所看到的闭包知识,同时也希望本文是你看的最后一篇关于闭包的文章。 大家看本文中的配图时,请牢记箭头的指向。因为它是根

    微信小程序闭包问题引发的JS闭包解决方案

    在网上搜索学习关于闭包的技术时发现讲的都比较抽象【我是菜鸟】,不好理解闭包的概念以及使用方法。今天我们带着疑问去学习:首先我给大家还原一下需求场景;对需求场景进行分析;引入闭包解决方案;升华闭包概念...

    最简单的例子让你轻松理解JavaScript闭包

    在理解闭包之前,为了让大家更好的理解闭包,我举一个形象的例子。在JS里有着作用域的概念,那么作用域是什么呢?有什么用呢?下面这个例子能形象的体现 比如每一座城市,城市里乡镇啊有公园,超市等,这些建筑设施...

    轻松理解JavaScript闭包

    下面列举出常见的闭包实现方式,以例子讲解闭包概念 function f1(){  var n=999;  nAdd=function(){n+=1}  function f2(){  alert(n);  }  return f2;  }  var result=f1();  result(); // 999  ...

    js学习之—-深入理解闭包

    闭包算是js里面比较不容易理解的点,尤其是对于没有编程基础的人来说。 其实闭包要注意的就那么几条,如果你都明白了那么征服它并不是什么难事儿。下面就让我们来谈一谈闭包的一些基本原理。  闭包的概念 一个闭包...

    python丨闭包丨装饰器.zip

    理解函数概念和闭包的语法特点 掌握装饰器函数的应用场景和特点、语法 能够实现装饰器函数 装饰有任意函数参数、返回值 了解类装饰器形式、理解可调用对象的概念 能够掌握装饰器带参数-装饰器工厂的意义和特点 理解...

    javascript闭包概念简单解析(推荐)

    关于”闭包”这个概念的文章在网上铺天盖地,基本已经稀烂了,但是有时候总感觉读了这么多的文章还是云山雾罩,当然是由于它本身就比较难于理解和涉及的知识较多,还有一个很重要的原因就是网上很多教程介绍可能存在...

    理解javascript闭包

    主要帮助大家理解javascript闭包概念优缺点及应用,帮助大家全面的学习javascript闭包,需要的朋友可以参考下

    基于javascript 闭包基础分享

    如果对作用域,函数为独立的对象这样的基本概念理解较好的话,理解闭包的概念并在实际的编程实践中应用则颇有水到渠成之感。在DOM的事件处理方面,大多数程序员甚至自己已经在使用闭包了而不自知,在这种情况下,...

    javascript 避免闭包引发的问题

    闭包的功能强大,但如果没有正确理解闭包的概念,其结果往往出乎人的意料。例如,下面是一个较常见的问题

    理解javascript中的闭包

    闭包在javascript来说是比较重要的概念,平时工作中也是用的比较多的一项技术。下来对其进行一个小小的总结 什么是闭包? 官方说法: 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在...

    JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解

    很早就接触过闭包这个概念了,但是一直糊里糊涂的,没有能够弄明白JavaScript的闭包到底是什么,有什么用,今天在网上看到了一篇讲JavaScript闭包的文章(原文链接),讲得非常好,这下算是彻底明白了JavaScript的闭包...

    对Python闭包与延迟绑定的方法详解

    Python闭包可能会在面试或者是工作中经常碰到,而提到Python的延迟绑定,肯定就离不开闭包的理解,今天总结下 关于闭包的概念以及一个延迟绑定的面试题。 Python闭包 1、什么是闭包,闭包必须满足以下3个条件: 必须...

Global site tag (gtag.js) - Google Analytics