序:很多人在面试被问到闭包时,都是回答闭包就是函数包着函数,闭包里的变量不会被销毁而云云等等。并且有很常多初学者都困惑为什么经常被问闭包?好像工作中也不常用到啊。其实问闭包就是要考你的基础扎不扎实,闭包也经常会用到,只是现在很多框架都封装好了,不需要我们直接去建闭包函数了。
几个基础概念的理解
执行环境(execution context),又称执行上下文,(js高级程序设计书中也称为作用域),指变量或函数执行操作的区域(执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。),分为全局执行环境(window)和函数拥有的局部执行环境。
执行流:从全局执行环境开始,向各个层级的局部执行环境中流去,每流向一个执行环境中就驱动此执行环境的操作(当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境),也象征着程序的执行顺序。
作用域链(scope chain):规定了对执行环境中的所有变量和函数有序访问的顺序链,此链的开端就是当前执行环境,逐层向外层延伸,末端是全局执行环境。标识符的搜索永远都是从作用域链的开端到末端。
此处有一个重要的设计特点:内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数
闭包理解
于是闭包就出场了,闭包就是将外部执行环境和内部执行环境连接起来的一座桥梁,可以通过闭包创建用于访问内部执行环境变量(私有变量)的特权方法。
闭包的常见方式,就是在一个函数内部创建另一个函数
闭包的应用场景:
● setTimeout 传参
● 模范块作用域
● 不暴露出去的私有变量和特权方法
为何闭包会导致内存泄露?如何回收此内存?
每个执行环境都有一个表示变量的对象——变量对象,作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
通常,当函数执行完毕后,函数局部的变量对象和作用域链就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。
闭包的情况是:外部函数执行完后,返回了一个匿名函数。此时外部函数的作用域链被销毁了,但是匿名函数的作用域链仍然在引用外部的变量对象。所以外部的变量对象会存在内存中,直到匿名函数被销毁,它才会被销毁。
回收内存的方法是:将此闭包的使用变量设为null,例如:
function bb (){
let a = 'sss'
return function(){
let aa = a++
}
}
let use = bb()
// ...... 使用过程
// 使用完后
use = null
根据以上思路分析和回答闭包的面试题是不是有机会脱颖而出呢?如果我有帮助到你,希望可以 三连支持下。
参考文献:
《JavaScript高级程序设计》