闭包的一些理解

基于 《你不知道的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() 是个闭包。

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

你可能感兴趣的:(闭包的一些理解)