预编译 闭包 作用域链

584 阅读2分钟

预编译

先GO后AO AO执行顺序

  1. 先形参定义 变量提升
  2. 形参实参统一
  3. 函数提升并且定义赋值

闭包

函数内部 return 一个内部函数被外部变量接收 外部变量可以使用内部函数 AO 中的值 闭包的好处是可以防止全局变量污染,但是闭包多了也会有内存泄漏的风险

function test1(){
    function test2(){
        var b =1
        console.log(a)
    }
    var a = 3
    return test2
}
var c = 3
var test3 = test1()
test3() //3

答案是 3

GO:{
    c:3
    test3:func
    test1:func
}

test1.AO:{
            a:3
            test2:func

        }
test2.AO:{
    b:1
}
test2.[[scope]] = test2.AO->test1.AO->GO

tips:闭包里保存的变量有点像 class 里面的类方法(只是形式像其实不一样)

function myMath1(num){
    var num=num
    function myAdd(){
        return num+1
    }
    function myReduce(){
        return num-1
    }

    return [myAdd,myReduce]

}

function myMath2(num){

    var num=num;
    var options = {
        add:function myAdd(){
        return num+1
        },
        reduce:function myReduce(){
        return num-1
        }
    }

    return options
}


var a = myMath1(10)
a[0]() //11
a[1]() //10

var b = myMath2(10)
b.add() //11
b.reduce()//10

作用域链

function a(){
    function b(){
        let c = 1
    }
    b()
}
a()
  1. 全局生成 GO:{a:func}
  2. a 函数被定义时系统生成 [[scope]]属性,[[scope]]保存该函数的作用域链,该作用域链里的第 0 位存储 GO
  3. a 函数在被执行时(前一刻)进行预编译生成 a 函数的 AO(执行上下文),同时作用域链的第 0 位存储 a 函数的 AO,同时第 1 位存储 GO。查找变量是到 a 函数存储的作用域链中从上往下依次查找。
  4. a 函数预编译时定义 b 函数,生成 b 函数[[scope]]
  5. b 函数被定义时是在 a 函数环境下,所以 b 函数此时的作用域链就是 a 函数被执行时的作用域链
  6. b 函数被执行时(前一刻)进行预编译生成 b 函数的 AO(执行上下文),b 函数 scope 第 0 位存储 b 函数 AO,第 1 位存储 a 函数的 AO,第 2 位存储 Go
  7. b 函数执行完后 b 函数的 AO 被销毁,回归被定义时的状态
  8. a 函数执行完后 a 函数的 AO 被销毁,b 函数的[[scope]]也不复存在,a 函数回归被定义时的状态

tips:

  1. 上级执行(执行前一刻预编译),下级定义
  2. 定义时生成作用域链 scope,执行时(执行前一刻)生成 AO