闭包
定义
- 如何产生闭包
- 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
- 闭包到底是什么
- 闭包是嵌套的内部函数
- 包含被引用变量(函数)的对象
- 闭包存在于嵌套的内部函数中
- 产生闭包的条件
- 嵌套函数
- 内部函数引用了外部函数的数据(变量/函数)
js
function fn1() {
var a = 1
function fn2() {
console.log(a)
}
}
fn1()
常见的闭包
将函数作为另一个函数的返回值
jsfunction fn1() { var a = 1 function fn2() { a++ console.log(a) } return fn2 } var f = fn1() f() // 3 f() // 4
将函数作为实参传递给另一个函数调用
jsfunction showDelay(msg, time) { setTimeout(function() { alert(msg) }, time) } showDelay('闭包', 2000)
作用
- 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
- 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
值得注意
- 函数执行完后,函数内部声明的局部变量一般不存在,存在于闭包中的变量才可能存在
- 在函数外部不能能直接访问函数内部的局部变量,但是可以通过闭包让外部操作它
生命周期
在嵌套内部函数定义执行完时就产生了(不是在调用)
在嵌套的内部函数成为垃圾对象时,就消失了
jsfunction fn1() { var a = 1 // 此时闭包已产生(函数提升,内部函数对象已经创建) function fn2() { a++ console.log(a) } return fn2 } var f = fn1() // 产生闭包 f() // 3 f() // 4 f = null // 闭包消失,包含闭包的函数对象成为垃圾对象
应用
定义
js模块
js// myModule.js function myModule() { // 私有的变量数据 var msg = 'my module' function do() { console.log('do' + msg) } function other() { console.log('other' + msg) } // 向外暴露对象或方法 return { do: do, other: other } } // main var m = myModule() m.do() m.other() // myModule2.js (function(w) { var msg = 'my module' function do() { console.log('do' + msg) } function other() { console.log('other' + msg) } // 向外暴露对象或方法 w.myModules = { do: do, other: other } })(window) // main 更优化的方法,可直接引用使用 myModules.do() myModules.other()
闭包的缺点
- 函数执行完成后,函数内的局部变量没有释放,占用内存时间会变长
- 容易造成内存泄漏
怎么解决
- 能不用就不用
- 及时释放
内存溢出和内存泄漏
内存溢出
- 一种程序运行出现的错误
- 当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
内存泄漏
- 占用的内存没有及时释放
- 内存泄漏积累多了就容易导致内存溢出
- 常见的内存泄漏
- 意外的全局变量
- 没有及时清理的计时器或回调函数
- 闭包