闭包的一些理解

基于 《你不知道的JavaScript上卷》 谈谈自己对闭包的理解。

首先明确下闭包的定义, 当函数可以记住并访问所在的词法作用域,就产生了闭包,即使函数是在当前词法作用域之外执行(关于作用域和词法作用域,大家可以搜搜其他文章,这里就不做多解释啦);

可以将闭包定义总结成三点: 

            1.一定是函数对象

            2.函数能够在其词法作用域被访问 (这个外,包含 空间和时间

            3.使得作用域的生命周期得以延续。(第二点和第三点相辅相成)

还有一句比较重要的概念,需要谨记:

            在JavaScript中函数是运行在被定义时的作用域中的,而不是运行环境的作用域

下面我们看段代码,理解下闭包:

图1
图2

先看图1,foo() 函数中定义了 bar() 函数,因此bar() 的词法作用域可以访问foo() 的内部作用域。

根据闭包的定义,图一的函数并不是闭包,因为bar封闭在了foo() 内部,函数不能在定义时的词法作用域外被访问。

再看图2,函数bar() 是被定义在foo() 函数作用域中,同样bar() 的词法作用域可以访问foo() 的内部作用域,foo() 函数返回bar() ; foo() 函数执行后的返回值 即 bar() 函数的对象,之后赋值给了baz变量。调用baz() ,实际上调用内部函数bar() ;

根据我们总结得闭包三点定义,我们再来看这个函数,首先bar()  是个函数,满足第一点,是函数对象。 

其次,baz() 的调用相当于在 全局作用域中调用了foo() 作用域中的bar() 函数,满足第二点,函数能后再其词法作用域外被访问。(这里的外指的空间之外)

最后,通常来说,foo() 函数运行完之后,整个内部作用域会被垃圾回收清理掉,但是由于bar() 的存在,为了供bar在以后时间被调用,bar() 保持对foo整个内部作用域的引用,因此foo() 无法被垃圾回收,换句话说,就是foo的内部作用域生命周期得以延续

为了加深理解,我们再看一段代码:

图3

wait() 函数内部 定义了 setTimeout() 函数,setTimeout()函数 有回调韩式timer() 。

timer() 函数就是闭包,可能某些人不能理解,我们在用闭包定义来分析,

首先 timer() 是个函数,满足上文总结得闭包定义第一点。

其次 timer() 函数是在 wait()执行后 1000ms 被调用, 满足第二点要求 。 timer() 所在的词法作用域是wait函数的内部作用域。wait()在执行1000ms后,timer()仍保留对wait()作用域的访问。满足了 函数能够在其词法作用域之外被访问,而此时的外 指的就是时间之外。

最后,wait()作用域由于 timer() 函数,生命周期得以延续,满足第三点。

所以,timer() 是个闭包。

以上是个人的一些理解,如果不同意见,欢迎讨论。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 10,917评论 16 88
  • 特别说明,为便于查阅,文章转自https://github.com/getify/You-Dont-Know-JS...
    杀破狼real阅读 3,379评论 0 0
  • 写这篇文章的原因很简单,临近毕业,不得不考虑找工作的问题,面临着就业的压力,开始在前辈的教育下,开始刷题之旅,从l...
    BeLLESS阅读 4,516评论 0 2
  • 以前看过好多文档,对于闭包不是很理解,再读《你不知道的JavaScript》上卷之后,终于明白了,感谢这本书,把自...
    晴風無眠阅读 3,142评论 0 1
  • 闭包是由函数和与其相关的引用环境组合而成的实体(wikipedia-闭包) 闭包由两部分组成:一是函数,二是与这个...
    WWWKY阅读 1,560评论 0 0