作用域
作用域是程序源代码中定义的范围。JavaScript采用词法作用域,也就是静态作用域。所谓词法作用域就是在函数定义的时候就已经确定了。
let value = 1
function foo(){
    console.log(value)
}
function bar(){
    let value = 2
    foo()
}
bar()  // 1
 
变量对象是当前代码段中,所有的变量(变量、函数、形参、arguments)组成的一个对象。变量对象分为全局变量对象和局部变量对象。全局简称为Variable Object VO,函数由于执行才被激活称为Active Object AO。
作用域链。在js中,函数存在一个隐式属性[[scopes]],这个属性用来保存当前函数的执行上下文环境,由于在数据结构上是链式的,因此也被称作是作用域链。我们可以把它理解为一个数组,可以理解为是一系列的AO对象所组成的一个链式结构。
作用域链的变量只能向上访问,直到访问到 window 对象终止。作用域链执行完会销毁。
function fn (){
}
console.dir(fn)
 

function fn (){
    console.dir(fn)
}
fn()
 

let global
function a() {
    let aa = 123
    function b() {
        let bb = 234
    }
    b()
}
a()
 
- 当 a 定义时,VO 包含 this(window), a(function), global
 - a 调用时,加入 a 的 AO 包含 this(window), arguments, b(function)
 - b 函数生成(a 函数的调用导致 b 函数的生成)
 - b 函数调用,b 函数的 AO 包含 this(window), arguments, bb
 
闭包
之所以没有及时被垃圾回收机制回收,是因为作用域链没有断裂。
let global
function a() {
    let aa = 123
    function b() {
        console.log(aa)
    }
    return b
}
let res = a()
res()
 
闭包实际应用
回调函数,防抖节流,定时器传参,手写 js (bind…),封装某些方法。
一道笔试题

function add(n) {
    let sum = n;
    function innerAdd(nextNum) {
        if (nextNum !== undefined) {
            sum += nextNum;
            return innerAdd;
        } else {
            return sum;
        }
    }
    return innerAdd;
}
console.log(add(1)(2)()); // 3
console.log(add(1)(2)(3)(4)()); // 10
console.log(add(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)()); // 10
                

















