定义
闭包是包含引用变量(函数),存在于嵌套的内部函数中的对象,有权访问另一个函数作用域中变量的函数
满足一下三点即为闭包:
- 函数嵌套
- 内部函数引用了外部函数的数据(变量/函数)
- 执行外部函数(外部函数定义后产生)(不需要调用内部函数)(内层函数返回外部,并且被全局变量保存)
function fn1() {
let a = 10;
function fn2() {
console.log(a);
}
fn2();
}
fn1();
特点
- 闭包的作用链包含自己本身的作用域、包含它的函数的作用域和全局作用域
- 注意事项:该函数作用域会一直保留到闭包不存在为止
作用
- 使局部变量在函数执行完后,仍然存活在内存中,延长了局部变量的生命周期
- 让外部可以操作(读写)到函数内部的数据(变量/函数)
- 可以避免使用全局变量,防止全局变量污染;
- 可以让局部变量常驻在内存中;
- 函数作用域的作用就是隔离变量,所以一般情况是看不了的
- 内部看的了外面(通过作用域链),外部看不了内部
- 可以实现外部无法操作,只能执行特定的写操作(如a++)和读操作
- 相当于是向外部暴露了一个固定的调用接口【当将函数作为返回值】
- 闭包存在没有消失的原因是外部有引用所以没有自动释放
生命周期
- 产生:在嵌套内部函数定义执行完时就创建了(不是调用)
- 死亡:在嵌套的内部函数成为垃圾对象时
应用
常见使用情况
- 将函数作为返回值
- 将函数作为实参传递给另一个函数调用
自定义js模块
- 即具有特定功能的js文件
- 将所有的数据和功能都封装在一个函数内部(私有的)
- 只能向外暴露一个包括n个方法的对象和函数
- 模块的使用者只需要通过模块暴露的对象调用方法来实现对应的功能
其他
- 保存settimeout等异步执行函数数据
- 封装私有变量
- 函数防抖
- 回调函数
闭包缺点
函数执行完后,函数内局部变量没有释放,占用内存时间边长
容易造成内存泄漏
解决
能不用闭包就不用,及早释放
- delete
- 引用=null,解除引用
内存泄漏和内存溢出
内存溢出
一种程序运行时出现的错误
当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
内存泄漏
占用的内存没有及时释放
内存泄漏多了就容易内存溢出
常见的内存泄漏
- 意外的全局变量(不加var在函数内定义)
- 没有及时清理的定时器或回调函数
- 闭包