闭包理解
1.闭包的产生
当一个嵌套的内部函数(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包。
2.闭包到底是什么?
廖雪峰:闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
理解一(大部分人的理解):闭包是嵌套的内部函数
理解二(少部分人的理解):包含被引用变量(函数)的那个对象(这个对象存在于嵌套的内部函数中)
可以使用开发者工具来调试查看。
3.产生闭包的条件?
(1)存在函数嵌套
(2)嵌套的内部函数必须引用在外部函数中定义的变量(函数)
(3)外部函数被执行(内部的函数不用执行,只需要执行其函数定义就已经产生闭包)
4.产生了几个闭包
闭包被创建了几个,就是外部函数被执行了几次,产生了几个内部函数对象,因为闭包就是内部函数,只有执行外部函数才会去创建内部函数,和内部函数被执行几次没有关系。
常见的闭包
1.将函数作为另一个函数的返回值
2.将函数作为实参传递给另一个函数调用
闭包的作用
1.闭包所使用的函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
2.让函数外部可以操作(读写)到函数内部的数据(变量/函数)
问题:
1.函数执行完后,函数内部声明的局部变量是否还存在?
一般是不存在的,存在于闭包中的变量才可能存在
2.在函数外部能直接访问函数内部的局部变量吗?
不能,但是如果有包含这个局部变量的闭包,我们就可以通过闭包让外部操作它
代码理解
1.这是上面常见的闭包中的1中的代码
2.执行fn1将会产生两个闭包,fn2和fn3
3.第23行如果只有fn1(),是会产生两个闭包,但产生完就没了,因为fn2和fn3是局部变量
4.第23行用f保存了fn3函数对象的引用,fn3变量是消失了,但它所指向的这个函数还存在于f中,所以这个闭包还存在
5.第24行代码并不是说执行了fn3,fn3早没了,执行的是f,f函数和fn3一样而已
6.就是因为4中所说的这个闭包的存在,第24行执行结果才会是1,因为fn1的变量a被保存在这个闭包中,也就体现了闭包的作用中的1(访问到了a),2(a--,操作了a),也体现了问题中的1(a还存在),2(操作了a)
闭包的生命周期
1.产生
在嵌套内部函数定义执行完就产生了(不是在调用时)
2.死亡
在嵌套的内部函数成为垃圾对象时
闭包应用:定义JS模块
JS模块
具有特定功能的js文件(特定功能:有些函数,操作一些数据)
将所有的数据和功能都封装在一个函数内部 (私有的) (要想私有必须放到一个函数中,对象的属性是直接可见的)
只向外暴露一个包含n个方法的对象或函数
模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
代码1
代码2
代码1使用先要执行函数,代码2使用起来,更直接更方便
闭包的缺点
1.缺点
函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
容易造成内存泄露
2.解决
能不用闭包就不用闭包
及时释放
内存溢出与内存泄漏
1.内存溢出
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
2.内存泄漏
占用的内存没有及时释放
内存泄漏积累多了就容易导致内存溢出
常见的内存泄漏:
意外的全局变量(在函数内部定义的全局变量,以为是局部变量)
没有及时清理的计时器或回调函数
闭包(没有及时释放,导致一直占用内存)
测试题
测试题1
测试题2
测试题3
循环遍历加监听
点击三个按钮分别显示它是第几个
1.普通实现
2.利用闭包实现
学识浅薄,如有错误,恳请斧正,在下不胜感激。
闭包:闭包理解 常见的闭包 闭包的作用 闭包的生命周期 (闭包应用:定义JS模块) 闭包的缺点 内存溢出与内存泄漏 测试题 循环遍历加监听