JavaScript闭包底层解析

1. 闭包是一个函数,这个函数有权访问另一个函数作用域中的变量,创建闭包最常见的方式,就是在函数内部创建函数。要想彻底搞清其中细节,必须从函数从创建到调用的时候都发生了什么入手

2. 函数第一次被调用,创建一个执行环境,和相应的作用域链

3. 作用域链赋值给一个特殊的内部属性Scope

4. 使用this,arguments和其他命名参数的值初始化函数的变量对象

5. 在作用域链中,内部函数的活动对象处于第一位,外部函数的活动对象始终处于第二位……直至全局执行环境

6. 执行函数时,为读取写入变量的值,需要在作用域链中查找变量

function compare(a  ,b){
            if(a<b){
                return -1;
            }else if(a>b){
                return 1;
            }else{
                return 0;
            }
        }
        var result = compare(5,10);    //    -1
        
1. 第一次调用compare()函数时,会创建一个活动对象,包括{this,arguments ,a,b}
2. 全局执行环境的变量对象{compare , result, this},在compare()的作用域链中处于第二位的

7. 每一个执行环境都有一个用来存放变量的对象——变量对象

  1.  全局环境中的变量对象始终存在

  2.  compare函数的局部环境的变量对象,只在函数执行过程中存在

8.  在创建compare函数时,先创建一个作用域链,这个作用域链预先就包含了全局变量对象

9. 作用域链保存在compare函数内部的Scope属性中

10. 调用compare函数时,会为函数创建一个执行环境,compare函数的局部变量对象被创建并放到作用域链的前端。

11. 所以,作用域链本质上是一个指向变量对象的指针列表,只引用但不实际包含变量对象

  1. Scope[{this,arguments ,a,b} , {compare , result, this}]

  2. compare函数在访问一个变量时,先从scope中第一个元素开始搜索,一个一个往后找

  3. 函数执行完毕后,局部变量对象被销毁,内存中仅存全局变量对象


1. 存在闭包就不一样了

2. 在函数内部定义的函数(子函数)会将外部函数(父函数)的变量对象添加到它(子函数)的作用域链中

function createCompareFunction(propName){
            return function(obj1 , obj2){
                var a = obj1[propName];
                var b = obj2[propName];

                if(a<b){
                    return -1;
                }else if(a>b){
                    return 1;
                }else{
                    return 0;
                }
            }
        }
        
        var compare = createCompareFunction('name');
        var result = compare({name:"Nico"} , {name:"Greg"});//true

1. 在内部的匿名函数的作用域链中,实际上包含外部函数的变量对象 2. 这个内部的匿名函数被return到外部后,这个匿名函数它的作用域链被初始化了 3. 包含createCompareFunction函数的变量对象以及全局变量对象 4. 所以,匿名函数可以访问createCompareFunction函数中所有的变量 5. 更为重要的是,createCompareFunction函数执行完毕被销毁后,其变量对象还有一份保存在匿名函数中,所以仍可以访问其内部的变量
原文地址:https://www.cnblogs.com/chaosJS/p/5663686.html