• 【代码】js闭包


    闭包

    • 闭包的英文是? closure

    • 函数为什么要有闭包特征呢?

      • 如果 A 函数中 声明了 B函数, B函数使用了 A函数作用域的属性

        常规操作: A函数执行结束后,会自动销毁其 函数作用域对象, 导致 x 被销毁, B函数会无法使用

        所以 B函数需要把 A函数的作用域保存在自身的 scopes 属性里

        B.scopes = [ 0: Closure A {x: 10} ]

        即 A函数作用域 是 B函数的闭包

        内层函数, 保存外层函数 作为自己的闭包

    • 利用闭包 我们可以做什么?

      • 防止全局污染

      • 把函数使用的变量 不在全局中声明, 而是在父级函数中声明, 存储在函数作用域

        固定格式:

        var 函数名 = (function(){ 
            var 变量 =return function(){  }
        })()
        
        • 1
        • 2
        • 3
        • 4
        • 5
    • 闭包的缺点? 消耗内存

      • 常规: 函数执行完毕后, 会自动销毁开辟的 函数作用域 对象
      • 但是: 因为闭包的存在, 导致对象无法被销毁, 会一直存在于内存中
    • 难以理解??

      • 在群众的呼声中: 2015年出版的 ES6 中, 提供了 let/const 搭配 块级/脚本 两个新生作用域, 比闭包使用更加方便快捷, 用于代替闭包
      • 但是: 你开发的软件为了兼容 2015年之前的浏览器, 例如 IE8, 就无法使用新特性, 只能用闭包
    DOCTYPE html>
    <html lang="en">
    
    
    <body>
      
    
      <script>
        // 函数对象中有一个属性: scopes -- 作用域们
        // 以 b 函数为例:
        // -- 第一个作用域: a函数作用域 -- 闭包
        // -- 第二个作用域: 全局作用域
    
        // 总结: 函数运行时会产生临时的函数作用域, 如果这个函数作用域被 子函数保存了, 则称为闭包
        // 具体: a函数作用域, 被 b函数保存在 scopes 属性里, 就说: a函数作用域是b的闭包
        // 为什么: b函数使用了 a 函数作用域中的变量, 假设b函数没有存, 则 a函数执行结束后会自动释放, 导致 b 函数中的 abb 无法使用
    
        function a() {
          var abb = 'ABB' // 此变量存储在 a函数作用域中
    
          function b() {
            // 根据上午提到的作用域链: b函数中没有变量 abb, 
            // 所以查找到 上级a函数作用域的abb
            console.log(abb);
          }
          return b
        }
    
        // b存储的是 a函数的返回值, 即 b 函数
        var b = a() // 调用函数a, 生成一个函数作用域
        b()
        console.dir(b) // dir: 直接输出函数对象, 与log不同
    
        // b函数使用了 abb 变量, 此变量存储在 a函数的作用域里, a函数执行完毕后, 则会自动释放函数作用域
        // 问: b() 调用时, 还能打印出 abb 变量么??
    
    
        var a = 5 //把 5 存放在变量 a 中
        var scopes = {}
        scopes.c = 10 //把10存储在 scopes对象的属性c里
    
        // 赋值操作 : 动名词结构
        var a = 10 //代表把 10 存储在 变量 a 中
    
        // a 中存储了 10 : 描述
    
    
        // 例如:
        // 涛哥想健身, 去健身房办卡
        // 过了几天后: 健身房倒闭了 -- 办卡无效
    
        // 闭包:
        // 涛哥想健身, 去健身房买了一套设备, 带回家
        // 健身房倒闭, 也没关系
      script>
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    DOCTYPE html>
    <html lang="en">
    
    
    
    <body>
      <script>
        // 1. 函数 调用时, 会形成临时的作用域对象, 在函数运行结束后会销毁, 节省内存
        function a() {
          var x = 10
    
          function b() {
            console.log(x)
          }
          return b
        }
    
        var b = a() //调用a函数, 生成函数作用域,
    
        // 函数执行完毕后 变量x 就会销毁
        b() // a()已经执行完毕, 理论上其生成的变量x 会销毁
        // b() 调用时, 还能读取到 x 吗?
    
        console.dir(b);
    
        // b函数会把 用到的变量所在的作用域保存在自身的 Scopes 属性里
        // 为了后期 调用时能够正常使用, 不怕销毁
    
        // a函数作用域销毁了吗?
        // 没有.  以为被b函数保存了
    
        // JS垃圾回收机制: 没用的东西会自动销毁
        console.log(window);
      script>
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    闭包应用

    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>闭包的应用 14:48title>
    head>
    
    <body>
      <script>
        // ES6之前的 旧时代, 有哪些作用域?   就两种
        // 全局  + 局部(函数)
        // 自定义变量存储在 全局里, 会造成全局变量污染
        // 那存放在哪里合适??   放局部 -- 即函数作用域
    
        // 记录函数调用的次数
    
        // 变量n 专为函数 a 而生, 存储在全局区就不合理 -- 公有的不安全 也 污染全局
        // 所以: 不能放全局作用
        // 就剩下局部作用域能放 -- 函数触发后生成
    
        // 思路: 利用 匿名函数自调用 快速形成函数作用域
        // (function(){})()  -- 下课去回顾 亮亮的 匿名函数自调用
        var n = 0
    
    
        function a() {
          n++
          console.log('n:', n);
        }
    
        a()
        a()
        a()
    
    
        // 声明函数的多种方案:
    
        // 1. 最普通
        function c() { }
    
        // 2. 匿名函数赋值给变量
        var c = function () { }
    
        // 3. 通过触发函数, 返回一个函数
        // d函数触发后, 返回一个函数交给变量 c
        var d = function () {
          // var x = function () { }
          // return x
    
          return function () { }
        }
        var c = d()
    
    
        // 4. 匿名函数自调用格式  (匿名函数)()
        var c = (function () {
          return function () { }
        })()
    
    
        // 4. 利用匿名函数 快速完成
        // 改写成匿名函数自调用
        var c = (function () {
          // var: 在哪个作用域中执行, 变量就提升到哪个作用域
          // 在 script 中用var, 就是全局window里
          // 在 函数{} 中用var, 就是函数作用域的
          var n = 0
    
          return function () {
            n++
            console.log('c的n:', n);
          }
        })()
        // (匿名函数)()
    
        // 思考: n是记录函数c调用次数的, 他是存在全局吗? 
        c()
        c()
        c()
        c()
        c()
        console.dir(c)
    
      script>
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
  • 相关阅读:
    用MicroPython开发ESP32-用TFT-LCD(ST7735S)显示图像
    面向对象编程原则(10)——总结
    Vue3 —— 常用 Composition API(二)(hook 函数、toRef 和 toRefs)
    wps阶梯表格怎么做?wps阶梯表格制作教程
    介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用。
    安卓APP源码和设计报告——好再来点餐
    jwbasta-vue 平台上线
    【开源电路】STM8S903K3T6C开发板
    队列(循环数组队列,用队列实现栈,用栈实现队列)
    智慧城市标准化白皮书(2022版)发布
  • 原文地址:https://blog.csdn.net/hdj0511/article/details/126599443