JavaScript 闭包的全面理解

写文章之前其实我对闭包的概念及原理模糊不清......
理解为一个函数内部返回一个函数,内部函数有权访问外层函数的作用域...来欺骗自己(很多这样的半吊子hhh)
其实这种说法没有绝对的对与错,写这篇文章其实就是为了自己在闭包的理解上能更深入更底层

讲闭包之前先讲下JavaScript的

执行环境(执行上下文),词法作用域,作用域链,垃圾回收机制

①执行环境(全局执行环境和函数执行环境):

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个相关联的变量对象(初始化阶段),这个对象里面保存了环境中定义的所有变量和函数。这个变量对象在编写代码是不能访问的,但解析器在处理数据时会在后台使用它。

全局执行环境是最外围的一个执行环境。ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样。在web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。当执行某个函数时,变量对象==》转换成活动对象,并把这个对象作为与该函数的执行环境关联的变量对象,从而创建出该函数的执行环境执行环境中代码执行完之后,该环境被销毁(执行栈,或环境栈将其环境弹出),保存在其中的所有变量和函数定义也随之销毁,随后控制权返回给之前的执行环境(全局执行环境直到应用程序退出–例如关闭网页或者浏览器时才会一一销毁)

图例1:

var name = 'window';
outer();
function outer(){
    var name = 'outer';
    inner();
    function inner(){
        var name = 'inner';
        console.log(name);//inner
    }
}

JavaScript 闭包的全面理解

②词法作用域:

简单地说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变(除动态作用域)

JS中代码整个的执行分两个阶段:代码编译和代码执行
1.代码编译:由编译器完成,将代码翻译成可执行代码。在代码编译阶段,作用域规则就已经被确定了。
2.代码执行:由js引擎完成,主要任务是执行可执行的代码。到代码执行时,执行上下文被创建,同时,作用域链作为作用域规则的具体实现被构建出来。
JavaScript 闭包的全面理解

:有兴趣了解词法分析器,动态作用域,可以查阅《你不知道的JS》上卷

③作用域链:

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量(即arguments对象,在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境。所以全局执行环境的变量对象始终都是作用域链中的最后一个对象

图例2:

function foo(){
    var a = 12;
    fun(a);
    function fun(a){
         var b = 8;
          console.log(a + b);
    }
 }  
 foo();

JavaScript 闭包的全面理解
④垃圾回收机制:

在Javascript中垃圾回收机制的原理很简单,找出那些不再继续使用的变量,释放其占用的内存。垃圾收集器会按照固定的时间间隔周期性的执行这一操作(常用方法就是标记清除,以及不太常见的引用计数)

:上面的内容可以翻阅《JavaScript高级程序设计第三版》

闭包(closure)

什么是闭包:引用github上一篇文章的话

当一个函数能够记住并访问到其所在的词法作用域及作用域链,特别强调是在其定义的作用域外进行的访问,
此时该函数和其上层执行上下文共同构成闭包。

需要明确的几点:
1.闭包一定是函数对象
2.闭包和词法作用域,作用域链,垃圾回收机制息息相关
3.当函数一定是在其定义的作用域外进行的访问时,才产生闭包
4.闭包是由该函数和其上层执行上下文共同构成

为什么要是函数对象呢?
函数可以提供一个执行环境,在这个环境中引用其它环境的变量对象时,后者不会被js内部回收机制清除掉。从而当你在当前执行环境中访问它时,它还是在内存当中的。千万不要把环境栈和垃圾回收这两个很重要的过程搞混了,环境栈调用移入,调用后移出,垃圾回收则是监听引用。

写不完了,要下班了,概念很抽象,明天撸几行代码解释一下