1. 定义
一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数), 因而这些
变量也是该表达式的一部分.
2. 简洁理解
- 一个函数定义在另一个函数内部
- 内部函数在执行时会通过复制它的[[scope]]属性创建作用域链
- 所以它会持外部父函数的变量对象的引用, 外部函数在执行完毕后不会马上释放变量对象的内存
- 因为作用域链上有外部函数等的变量对象, 所以常用于callback等用途
- 内部函数被调用时就会形成"闭包"
3. 深入理解
说到闭包, 就不得不提及变量对象和作用域链.
- 每个执行环境(既作用域)都有一个表示变量的对象—变量对象, 全局环境的变量对象始终存在, 局部环境的变量对象(如函数调用等), 则只在函数执行时存在.
- 再定义一个函数时, 会预先创建一个包含全局变量对象的作用域链, 保存在函数内部的[[scope]]属性中.
- 调用函数时, 会为函数创建一个执行环境, 通过复制函数的[[scope]]属性中的对象构建起执行环境的所需的新作用域链.
- 然后会有一个新的活动对象(即调用函数产生的变量对象)被创建并推入执行环境的作用域链的最前端.
- 作用域链本质上是一个指向变量对象的指针列表, 就是一个个指针从头到尾链了起来, 每个指针都指向一个变量对象.
- 无论什么时候在函数中访问一个变量, 都是从作用域链中搜索相应名字的变量.
- 一般来讲, 当函数执行完毕后, 局部活动对象就会被销毁, 内存中仅保存全局作用域, 但闭包不同, 因为闭包情况下, 外部函数的活动对象会被内部函数引用, 当内部函数的活动对象没被销毁时, 外部函数的活动对象是无法被释放的, 所以使用闭包时要注意内存泄露等问题.
- 当一个函数内部定义的子函数将会函数(即外部函数)的活动对象添加到他的作用域链中.
- 因为, 函数内部定义的匿名函数将会包含外部函数的活动对象, 即作用域链上有外部函数的变量对象, 从而实现了闭包. 因此外部函数不会在执行完后立即销毁活动对象, 因为内部的函数可能在引用. 只要内部函数执行完后, 才会执行销毁.