所在的位置: js >> js优势 >> js之闭包是如何产生的

js之闭包是如何产生的

在前两篇文章中,齐云道长介绍了作用域和执行上下文,也包括了变量对象、作用域链、变量提升的原理。为的就是在这里说出这句话——当代码写下的那一刻就注定了闭包的出现,这就是事物发展的规律。闭包的概念不少朋友搞不清闭包是什么,甚至和立即执行函数混淆,也有些朋友认为闭包就是一种特殊的函数,不过显然这么说是不准确的。闭包不是一种函数,而是一种现象:闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。我们知道词法作用域是代码写下的时候就形成了,执行环境是在函数调用的时候生成,在代码执行完会从执行环境栈中出栈回收。作用域、作用域链、执行环境都是形成闭包的因素。闭包是如何产生的在创建函数的时候,产生相应的执行环境,在执行环境里生成活动对象、作用域链。先利用作用域进行变量提升,然后顺序执行的时候,对变量进行赋值操作,执行完毕把执行环境从执行环境栈中弹出。fun()创建了自己的执行环境,里面有活动对象,进行了变量提升,执行完本来应该被弹出。然而返回的foo函数被赋值给bar,foo函数和fun函数的变量对象,组成了闭包。foo函数里要使用变量a,但是foo的执行环境里的并没有声明a,此时会沿着执行环境里的作用域链搜寻a的声明,由于foo包含着对fun的活动对象的引用,所以fun的活动对象一直没有被释放。这就是产生闭包的原因。作用域链的值赋给了执行环境内部的[[Scope]]属性,作用域链是数组形式,scope[0]是当前活动对象,scope[1]是外部函数的活动对象,……scope[leght-1]是全局变量对象。所以,什么是闭包?当某个函数的作用域链还引用着其他函数的活动对象时,就会形成闭包。闭包的应用es6出现之前,有个非常经典的问题——循环这个经典的问题是由于es6之前并没有块级作用域,所以i是全局变量,然后setTimeout的回调又是在循环结束才会执行,所以最终会每秒一次输出5,总共输出5次,而不是从1-5。我们通过闭包解决这个问题:我们通过立即执行函数,形成闭包,这样每次循环都会创建一个独立的执行环境,最终实现效果。当然es6之后,我们可以用let替代var,因为let可以生成块作用域。闭包另一个重要的作用是模块化,可以实现对私有变量的封装。本文是陈少棠原创,收录在《齐云札记》,转载请标明原作。


转载请注明:http://www.aierlanlan.com/grrz/7273.html

  • 上一篇文章:
  •   
  • 下一篇文章: