闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
创建作用域链过程及作用细节:
当某个函数第一次被调用时,会创建一个执行环境(execution context)及相应的作用域链(Scope Chain),并把作用域链赋值给一个特殊的内部属性(即[[Scope]])。然后,使用this、arguments和其他命名参数的值来初始化函数的活动对象(activation object)。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,……直至作为作用域链终点的全局执行环境。
在函数执行过程中,为读取和写入变量的值,就需要在作用域链中查找变量。
当调用函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。此后,又有一个活动对象(在此作为变量对象使用)被创建并被推入执行环境作用域链的前端。
作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
闭包情况下,即便内部函数被返回了而且在其他地方被调用了,它仍然可以访问外部函数变量,即内部函数作用域链中包含外部函数的作用域。
在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。而当这个函数执行完毕后,作用域链被销毁,而活动对象仍保留在内存中,直到函数被销毁(=null)。
因此闭包会携带包含它的函数的作用域,比其它函数更占内存,应谨慎使用。
参考资料:《Javascript高级程序设计》