理解闭包
1.如何产生闭包
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
2.闭包到底是什么
闭包是嵌套的内部函数
包含被引用变量(函数)的对象
注意:闭包存在于嵌套的内部函数中
3.产生闭包的条件
函数嵌套
内部函数引用了外部函数的数据(变量/函数)
function fn1() { // 此时闭包就已经产生了(函数提升,内部函数对象已经创建了) var a =2 function fn2() { a++ console.log(a) } return fn2 } var f = fn1() f() // 3 f() // 4 f = null // 闭包死亡(包含闭包的函数对象成为垃圾对象)
常见的闭包
1.将函数作为另一个函数的返回值
2.将函数作为实参传递给另一个函数调用
闭包的作用
1.延长局部变量的生命周期
2.从外部可以(间接)操作函数内部的局部变量
闭包的生命周期
1.产生:在嵌套内部函数定义执行完成就产生了(不是在调用时)
2.死亡:在嵌套内部函数成为垃圾对象时
闭包的应用
自定义JS模块
*具有特定功能得js文件
*将所有的数据和功能都封装在一个函数内部(私有的)
*只向外暴露一个包含n个方法的对象或函数
*模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
案例一
function myModule() { // 私有变量 var msg = 'Hello World' // 操作私有变量的函数 function upperCase() { console.log('upperCase()' + msg.toUpperCase()) } function lowerCase() { console.log('lowerCase()' + msg.toLowerCase()) } // 向外部暴露对象(给外部使用的方法) return { upperCase: upperCase, lowerCase: lowerCase } }
案例二
(function () { // 私有变量 var msg = 'Hello World' // 操作私有变量的函数 function upperCase() { console.log('upperCase()' + msg.toUpperCase()) } function lowerCase() { console.log('lowerCase()' + msg.toLowerCase()) } // 直接挂在window上 window.myModule = { upperCase: upperCase, lowerCase: lowerCase } })()
闭包的缺点以及解决
1.缺点
*函数执行完后,函数内的局部变量没有释放,占用内存时间变长
*容易造成内存泄漏
2.解决
*能不用闭包就不用
*及时释放 (赋值null)
闭包代码案例
代码一
var name = "window" var obj = { name : 'object', getName : function() { return function() { return this.name; } } } console.log(obj.getName()()) // window
代码二
var name = "window" var obj = { name : 'object', getName : function() { var that = this return function() { return that.name } } } console.log(obj.getName()()) // object
代码三
function fun(n, o) { console.log(o) return { fun: function(m) { return fun(m, n) } } } var aa = fun(0); // undefined aa.fun(1); // 0 aa.fun(2); // 0 aa.fun(3); // 0 var bb = fun(0).fun(1).fun(2).fun(3); // undefined 0 1 2 var cc = fun(0).fun(1); // undefined 0 cc.fun(2); // 1 cc.fun(3); // 1
内存溢出与内存泄漏
1.内存溢出
*一种程序运行出现的错误
*当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
2.内存泄漏
*占用的内存没有及时释放
*内存泄漏积累多了就容易导致内存溢出
*常见的内存泄漏
i意外的全局变量
ii没有及时清理的计时器或回调函数
iii闭包