闭包

当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包。
我们可以用浏览器的开发者工具来调试查看。
闭包可以有两种理解,闭包是嵌套的内部函数,另一种是包含被引用变量(函数)的对象

产生闭包的条件

函数嵌套内部函数引用了外部函数的数据(变量/函数),执行函数定义(调用外部函数,不用调用内部函数)

闭包的作用

使函数内部的变量在函数执行完后,仍然存活在内存中(延长局部变量的生命周期)
让函数外部能直接访问函数内部的局部变量
函数执行完后,函数内部声明的局部变量一般不存在,存在于闭包中的变量才可能存在
产生在嵌套内部函数定义执行完时就产生了(不是在调用)

function fn1() {
    var a = 2
    function fn2() {
        a++
        console.log(a)
    }
    return fn2
}
var f = fn1()
f()//3
f()//4
f = null//闭包死亡(包含必报的函数对象成为垃圾对象)

闭包的应用

定义js模块
具有特定功能的js文件,将所有的数据和功能都封装在一个函数内部(私有的)。
只向外暴露一个包含n个方法的对象或函数.模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
以下是两种使用方法

//1.js
function myModule(){
  //私有数据
  var msg='I am Xmy'
  //操作数据的函数
  function dosomething(){
​    console.log('dosomething()'+msg.toUpperCase())
  }
  function dootherthing(){
​    console.log('dootherthing()'+msg.toLowerCase())
  }
  //向外暴露对象
  return {
​    dosomething:dosomething,
​    dootherthing:dootherthing
  }
  // 返回了一个对象,这个对象有两个方法,方法名可以改
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
    <script type="text/javascript" src="./1.js"></script>
    <script type="text/javascript">
​    var module=myModule()
​    module.dosomething()
​    module.dootherthing()
  </script>
</body>
</html>
}

//2.js
function myModule(){
    //私有数据
    var msg='I am Xmy'
    //操作数据的函数
    function dosomething(){
        console.log('dosomething()'+msg.toUpperCase())
    }
    function dootherthing(){
        console.log('dootherthing()'+msg.toLowerCase())
    }
    //向外暴露对象
    return {
        dosomething:dosomething,
        dootherthing:dootherthing
    }
    // 返回了一个对象,这个对象有两个方法,方法名可以改
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript" src="./2.js"></script>
    <script type="text/javascript">
        myModule2.dosomething()
        myModule2.dootherthing()
    </script>
</body>
</html>

闭包的缺点和解决

函数执行完后,函数内的局部变量没有释放,占用内存时间会变长。容易造成内存泄漏
解决:让内部函数成为垃圾对象-->回收闭包

内存溢出

一种程序运行出现的错误

内存泄漏

占用的内存没有及时释放,内存泄漏积累多了就容易导致内存溢出。
内存中容易出现的内存溢出
1.意外的全局变量
2.没有及时清理的计时器或回调函数
3.闭包

function fn(){
    a=new Array(10000000)
    console.log(a)
}
fn()
//这里没有使用var,默认在window中定义。


var interid =setInterval(function(){
    console.log('---')
}, 1000);
//启动循环定时器后不清理
clearInterval(interid)
//清理定时器

Q.E.D.