首先闭包表示有权访问另一个函数作用域中的变量的函数,常见的创建闭包的方式是在一个函数中创建另一个函数。
要了解闭包的原理首先要了解函数作用域,接下来从函数作用域推广到闭包的原理。
1、当某个函数被调用时,会创建一个执行环境及相应的作用域链。然后使用arguments和其他参数的值来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位, 外部函数的外部函数的活动对象处于第三位,……以此类推,直至作为作用域的全局执行环境。
2、在函数执行过程中,为读取和写入变量的值,就需要在作用域中查找变量,依次按照内部-》外部-》外部的外部的顺序进行查找。
3、一般来讲,当函数执行完毕之后,局部活动对象就会被销毁,内存中均保存全局作用域(全局执行环境的变量对象),但是,闭包的情况不一样:在另一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕后,其活动对象也不会被销毁,因为内部函数的作用域链仍然在引用这个活动对象。所以当函数执行完毕后,只是执行的作用域链会被销毁,但它的活动对象仍然保留在内存中,知道内部函数被销毁后才销毁。这就是闭包的原理。
注意:由于闭包具有以上特性,所以导致闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度的使用闭包可能会导致内存占用过多,虽然像V8等优化后的js引擎会尝试回收被闭包占用的内存,但还是建议在绝对必要的时候再使用闭包。