都说闭包是javaScript中一个近乎神话的概念,我刚好碰到这个神话,想着怎么把它讲成一个故事!javaScript中闭包无处不在的,我们要做的是识别和拥抱它。
闭包到底是什么?
当函数可以记住并访问所在的词法作用域(不论函数是否在当前的词法作用域内执行),就产生了闭包。当然,这是官话,学术语气太强了理解起来很难受,所以我用自己的理解+接地气的语言来诠释一下这句话,我觉得在此同时,我们可以将闭包的缺陷一起了解一下。下面我们来看两段代码:
这里的两段代码执行的都是将原有的a变量重新赋值并打印出来,我们先来看(当函数可以记住并访问所在的词法作用域(不论函数是否在当前的词法作用域内执行),就产生了闭包)这句话怎么理解,看图2。
首先要明白,产生闭包的先决条件是函数的嵌套使用!
其次再来理解概念:函数 wn() 包含在 foo() 的内部,它的词法作用域能访问到 foo() 的内部作用域,我们将 wn() 对象本身作为返回值返回给 foo(),foo() 执行后,其返回值(也就是内部的 wn() 函数)赋值给了psc,并调用执行了 psc() ,实际上只是通过不同的标识符引用,来调用了内部函数 wn()。到这里这些文字应该都比较好理解对吧!!!!好的睁大眼睛看下面这句话很重要:函数 foo() 并不是自执行函数,图2代码的执行顺序并不是从上往下依次执行的这个也能理解的吧?!代码是执行到最后的 psc() 调用的时候才返回去找 psc 是什么,好的找到了 psc 是函数 foo() 的赋值,然后再去找 foo() 是什么,找到 foo() 这个函数的时候才依次从上向下执行内部的代码。刚刚我们就分析过了,图2的代码其实际上只是通过不同的标识符引用最终调用的是 wn() 函数,在这个过程中,wn() 即实现了调用输出,而它的词法作用域又保存完成整——这就是闭包的概念。
无论通过何种手段将内部函数(这里指的是 wn() )传递到所在的词法作用域以外,它都会持有对原始定义的作用域的引用,无论在何处执行这个函数,都涉及到使用闭包这一概念。
——另外,图1放上来的作用一直没说,其作用就是用来对比图2,3。浏览器的引擎有垃圾回收机制(想要了解原理的自行去谷歌)。图1中当foo() 调用完成,该函数内部将全局变量 a 赋值成了 2,当我们可以拿到这个为 2 的 a 来用时,事实上,这个 foo() 函数已经功成名就,这个时候,虽然代码还是在我们写的js文件中,但是对于浏览器来说,这个已经执行过的 foo() 函数宣布退隐江湖,也不再给它分配作用域空间了,foo() 的内容也不再被使用了,引擎默认这样做的意义是释放浏览器不再使用的内存空间,这相当于是引擎的自动优化功能。而 闭包,这个东西,一旦形成却是能阻止引擎的这一默认事件的发生,因为闭包形成了自己稳定完整的内部作用域,引擎已经拿它没有办法了(打不过,动不了它,这个还是跟引擎的工作原理有关系),这个稳定的内部作用域将永久的提供给 wn() 函数使用,所以拜 wn() 所声明的位置所赐,它将永久拥有并在任何时间使用这个涵盖 foo() 内部的作用域。——这就是闭包的缺点,不能释放不需要使用的作用域,如果一个项目中这样的闭包使用很多的话,对浏览器性能的消耗将大大提升。emmmmmmmmmm
不知道这样讲的够不够清楚,还不够通俗的话我emmmm.....绞尽奶汁再想想怎么解释?