闭包的产生

  今天要说的内容是闭包,闭包在JavsScript的重要性不言而喻,无论你是初级的还是高级的工程师,你都避不开闭包这个知识点。

要想搞清楚闭包的产生,那就必须明白JavaScript另一个非常重要的基础知识点-作用域链,之前提到过一次了,为了比较系统的讲解,这里再次从作用域出发。

作用域与作用域链

  作用域[[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不能访问,不能访问的属性仅供javascript内部调用,[[scope]]就是其中的一个。

[[scope]]指的就是作用域,其中存储了运行期上下文的集合(之前介绍的AO活动对象)

作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,这种链式链接就是作用域链。

看看如下代码:

  代码的执行分两个步骤:

    1)预编译

    2)函数执行

  在预编译环节会将全局变量字段组成一个Global Object(GO),而这个Global Object 会首先存入代码a函数的作用域里面(此时作用域里面只有一个Global Object),当代码运行时a函数会产生一个活动对象也就是运行时期的上下文,里面存有的字段属性都是a函数运行时确定的,看如下简易图解:

a函数运行前(通过预编译)

a函数运行后(产生AO)

  当a函数运行产生AO后便形成了一个作用域链,a函数运行时如果找某个字段,首先会从自己的AO中查找,如果没有再到GO中查找,比如查找global字段

  通过以上的讲解,想必明白一个函数的作用域是什么了吧,接下来要说的就是今天的主角-闭包

闭包的产生

  有好多初学者可能不知道天天念叨的闭包是如何产生的,我们看下面的例子:

  当a函数运行后,里面构成的作用域我们已经知道了,要明白AO的生命周期是在a函数运行完毕后自动销毁的,函数里面的return b;就宣布a函数运行完毕,而此时返回的是b函数的一个引用,这就等于又声明了一个b函数,注意b函数里面又用到了a函数里面的num字段,而a函数已经销毁了,这里就产生了闭包,我们做如下图解:

b函数声明:

  b函数声明的数据正是a函数运行后的GO+AOa函数运行结束后的销毁操作就是不再指向AO,回到最初声明的模样。

b函数运行:

  从图中可以看到即使a函数销毁,b函数依然拿着a函数当时运行所生成的AO,当然包括里面的各种属性字段,此时已然形成了闭包。

现在来看看闭包的定义

  闭包就是能够读取其他函数内部变量的函数

  知道什么是闭包了,接下来看一个小例子加深闭包的概念

输出结果:

b函数运行时,num++修改的是a函数运行时产生的AO里面的字段num

c函数运行时,num--修改的也是a函数运行时产生的AO里面的字段num

我们发现a函数运行所产生的AO成了公共的了,谁都可以调用修改,如下图:

  以上便是闭包产生的由来以及一个关于闭包的小例子,接下来的问题是,我们在写代码的时候都有哪些涉及到了闭包,闭包有什么作用等等,这些我会在后面讲解,下一期我会讲到一个非常经典的例子,利用闭包接君闭包产生的问题。

posted @ 2018-11-29 17:40  七音客  阅读(369)  评论(1)    收藏  举报