简介

image.png

本质就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放。

闭包作用 :

  1. 延伸了变量的 作用范围/生命周期
  2. 创建私有环境 ```javascript 上级作用域变量num被下级作用域内引用(return部分函数)形成闭包,不断调用fn会一直修改num变量 function fn() { var num = 10 return function () { console.log(num); num++; } } var f = fn() f(); //10 f(); //11

//重新开启一个闭包赋值给f,输出为10 var f1 = fn() f1()//10

//继续指向闭包f函数 输出12 f(); //12

  1. <a name="K08gw"></a>
  2. # 在chrom调试下查看是否闭包
  3. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1644759306331-55e43919-3589-4ca7-ae0b-7fe57c24b0fa.png#clientId=u95f199c8-6465-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ub67f955c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=293&originWidth=519&originalType=url&ratio=1&rotation=0&showTitle=false&size=91778&status=done&style=none&taskId=u1ccf17ba-98c1-4e01-9e1e-f7367692549&title=)
  4. <a name="mEEG8"></a>
  5. # 缺点及解决
  6. 1. 缺点
  7. - 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
  8. - 容易造成内存泄露
  9. 2. 解决
  10. - 能不用闭包就不用
  11. - 及时释放
  12. ```javascript
  13. function fn1() {
  14. var a = 2;
  15. function fn2() {
  16. a++;
  17. console.log(a);
  18. }
  19. return fn2;
  20. }
  21. var f = fn1();
  22. f(); // 3
  23. f(); // 4
  24. f = null // 垃圾对象 释放

内存溢出&内存泄漏

  1. 内存溢出
  • 一种程序运行出现的错误
  • 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
  1. 内存泄露
  • 占用的内存没有及时释放
  • 内存泄露积累多了就容易导致内存溢出
  • 常见的内存泄露:

    • 意外的全局变量
    • 没有及时清理的计时器或回调函数
    • 闭包 ```javascript

    // 1. 内存溢出 /var obj = {} for (var i = 0; i < 100000; i++) { obj[i] = new Array(10000000) } console.log(‘———‘)/

    // 2. 内存泄露 // 意外的全局变量 function fn () { a = [] //不小心没有var定义 } fn() // 没有及时清理的计时器 setInterval(function () { console.log(‘——‘) }, 1000)

<a name="oFNkV"></a>
# 案例
> 此时的每个立即执行函数就在开辟了内存,所有每个i都是独立的(每个函数都是一个闭包),都要等到点击之后才会销毁,所有闭包也占内存。

![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1644759306364-3ac8f049-b367-415e-a833-f5aa8c22c379.png#clientId=u95f199c8-6465-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=JWCMq&margin=%5Bobject%20Object%5D&name=image.png&originHeight=277&originWidth=759&originalType=url&ratio=1&rotation=0&showTitle=false&size=119417&status=done&style=none&taskId=ubda89100-67cc-46a3-ac21-3aafaf83904&title=)<br />与上边例子原理一样<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1644759306355-90c11395-f99c-4343-aa61-34fcd402e594.png#clientId=u95f199c8-6465-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=MM5iA&margin=%5Bobject%20Object%5D&name=image.png&originHeight=203&originWidth=637&originalType=url&ratio=1&rotation=0&showTitle=false&size=94911&status=done&style=none&taskId=u3e6bfc40-eb38-4356-85e6-c5ae03e1544&title=)<br />该案例的注意点:

1. price和yd访问了上级作用域car的变量产生了闭包
1. 变量car接收了立即调用函数,此时内存空间中就有一个car和对应的变量start和total。当price被调用时修改了total=23,此时的total(23)是被price修改过后的,因此yd再执行时拿到total(23) 最后返回33。

![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1644759306410-fe0c58c0-4ea3-451a-80cf-97a654e3eff8.png#clientId=u95f199c8-6465-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=uHODY&margin=%5Bobject%20Object%5D&name=image.png&originHeight=526&originWidth=636&originalType=url&ratio=1&rotation=0&showTitle=false&size=173042&status=done&style=none&taskId=u63ebf410-79ff-48e9-a606-4be885fd092&title=)
<a name="f8Tlf"></a>
# 思考题1
左题: `object.getNameFunc().call(object)` 如果利用call改变this指向则输出的是'My Object'<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/1624878/1644759307172-b3b981b3-59c5-48b3-a5b5-b2817f4c1a9a.png#clientId=u95f199c8-6465-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=pYiXr&margin=%5Bobject%20Object%5D&name=image.png&originHeight=387&originWidth=748&originalType=url&ratio=1&rotation=0&showTitle=false&size=202306&status=done&style=none&taskId=uad5380a0-b089-4eb5-8724-7d29e44a774&title=)
<a name="X0C3e"></a>
# 思考题2
该题中 有无产生闭包可以理解为 是否有被接收且未被释放<br />第一个输出 如果是 `var b = a.fun(1);  b.fun(2)`则产生闭包 输出结果为//undefined,0,1,0<br />第二个输出 由于一直被接收 所以尝试了闭包<br />第三个输出 `fun(1)`后变为1,后续以c为主并且未产生闭包 所有都为1
```javascript
  function fun(n, o) {
    console.log(o)
    return {
      fun: function (m) {
        return fun(m, n)
      }
    }
  }

  var a = fun(0)
  a.fun(1)
  a.fun(2)
  a.fun(3) //undefined,0,0,0

  var b = fun(0).fun(1).fun(2).fun(3) //undefined,0,1,2

  var c = fun(0).fun(1)
  c.fun(2)
  c.fun(3) //undefined,0,1,1