本文基于《JavaScript高级程序设计》整理。
闭包概念:
闭包是一类函数。哪一类?有权访问 另一个 函数 作用域中变量的函数。
想要理解闭包,必须从理解函数被【调用】的时候会发生什么入手。
每次复习闭包的相关知识,我都习惯把作用域和闭包一起复习。
函数的作用域链
1.创建函数outerFun()时,会创建一个预先包含全局变量对象的作用域链,保存在内部的[[Scope]]属性中。
2.调用函数outerFun()时,为此函数创建一个执行环境。
3.然后复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。
4.此后,创建一个活动对象,推入执行环境作用域链的前端([0]位置)。
此时执行环境的作用域链中包含两个变量对象:全局变量对象(第3步) 、 局部活动对象(第4步)。
函数中访问一个变量时,就会从作用域链中搜索具有相应名字的变量。
函数执行完后,局部活动对象被销毁,内存中仅保存全局作用域。
闭包的情况
?内部函数 被 外部函数 包含时,内部函数会将外部函数的局部活动对象添加到自己的作用域链中。
outerFun(outerArgument){
//被包含的内部函数可以访问外部函数的变量
return function(){
return outerArgument+1
}
}
而由于内部匿名函数的作用域链 在引用 外部包含函数的活动对象 ,即使outFun执行完毕了,它的活动对象还是不会被销毁!
即,outerFun的执行环境作用域链都销毁了,它的活动对象还在内存中留着呢。
并且根据垃圾回收机制,被另一个作用域引用的变量不会被回收。
所以,除非内部的匿名函数解除对活动变量的引用(解除对匿名函数的引用),才可以释放内存。
// 创建函数 还未调用
var creatFun = outerFun(7)
// 调用函数
var result = creatFun(8)
// 解除对匿名函数的引用
creatFun = null
所以,闭包会造成内存泄漏,就是因为它把外部的包含它的函数的活动对象也包含在自己的作用域链中了,会比一般的函数占用更多内存。
如何减少闭包占用的内存问题?见下一篇:闭包如何减少内存占用?