写点什么

闭包

作者:Jason199
  • 2022 年 7 月 09 日
  • 本文字数:2654 字

    阅读完需:约 9 分钟

闭包

了解闭包:

        一个函数的高级应用

        官方的定义: 闭包就是指有权访问另一个函数作用域中的变量的函数

函数的两个步骤

        1. 函数定义

          1-1. 在堆里面开辟一个空间

          1-2. 把函数体内的所有代码当作字符串存储在这个空间中

          1-3. 把空间地址赋值给栈里面的变量(函数名)

        2. 函数调用

          2-1. 按照存储的地址找到 函数存储空间

          2-2. 再 调用栈(不是栈内存) 里面再次开辟一个 函数执行空间

          2-3. 在函数执行空间内进行 形参复制

          2-4. 在函数执行空间内进行 预解析

          2-5. 把 函数存储空间 的代码复制一份拿到 函数执行空间 里面执行

          2-6. 代码全部执行完毕, 这个新开辟的函数执行空间销毁

 function fn() {      var num = 100;      console.log('hello world');      num++;      console.log(num);    }    fn();    fn();
复制代码


一个不会被销毁的函数执行空间

        函数的每一次执行会创建一个函数执行空间

        当函数内部返回一个 复杂数据类型 的时候, 并且函数外部还有变量在接收

        这个函数执行空间不会被销毁,从而延长了函数的生命周期。

function fn() {      var num = 100      console.log('hello world')// 函数内部返回一个复杂数据类型      return {}    }// obj 接收的 fn 函数执行空间内部的 对象    const obj = fn()// 创建了一个新的对象返回    const obj2 = fn()     console.log(obj)
复制代码

形成闭包的条件

          1. 需要有一个不会被销毁的函数执行空间

          2. 函数内部 直接 或者 间接 的返回一个函数

          3. 内部函数操作(访问, 赋值)着外部函数的变量

        当以上三个条件都满足的时候

          内部的函数叫做外部函数的 闭包函数

闭包的作用

        1. 定义函数变量在函数内部就是私有变量

        2. 利用闭包函数访问帮助函数外部访问函数内部的私有变量

闭包的特点

        1. 保护变量私有化

          优点: 不去污染全局

          缺点: 外部不能访问, 需要闭包函数

        2. 可以在函数外部访问函数内部的变量

          优点: 不局限于私有变量

          缺点: 外部访问需要闭包函数

        3. 变量的生命周期

          优点: 变量的声明周期被延长了

          缺点: 一个不会被销毁的函数空间

        致命缺点: 一个不会被销毁的函数空间会导致内存泄漏

          所以要慎用闭包

function fn() {      var num = 100// fn 函数内部返回了一个 a 函数      return function a() {// 访问外部函数 fn 的私有变量 num// 并且把 num 的值返回        return num      }    }  // 此时, res 接收的是 - fn 函数内部的 a 函数  // 我们管 res 或者 a 叫做 fn 的闭包函数    const res = fn() // 返回 100 // fn 函数的私有变量 num    console.log(res())
复制代码

既然上面写到了闭包的缺点和比较致命的问题,接下来写一下如何销毁闭包。

闭包销毁

        1. 不销毁的空间

        2. 返回函数

        3. 内部函数引用外部函数变量

        你想销毁闭包的时候, 只要这个不销毁的空间不存在了, 闭包就没了

       什么是不销毁的空间:

          返回复杂数据类型的空间

          收有外部变量的空间

        如何销毁空间

          外部变量不再接收

          外部接收的变量被重新赋值

 function fn() {    var num = 100    return function a() {    return num      }    }// res 是 fn 的闭包函数    let res = fn()// res 存储的不再是 fn 函数内部返回的 函数了// fn 的执行空间销毁了    res = 100
复制代码

闭包的应用

沙箱模式

        是设计模式的一种: 为了解决特定问题给出的简洁而优化的解决方案

        目的是为解决 变量私有化以后的访问和操作问题。

function fn() {      var num = 100      var str = 'hello world'       function inner1() {        console.log('我是 inner1 函数')      }// 间接返回一个函数      return {        getNum: function () {          return num        },        setNum: function (val) {          num = val        }      }    }// res 接收的是 ? 一个对象, 对象里面有函数, 对象里面的函数, 使用着外部函数的变量    const res = fn()// 你想拿到 fn 函数内部的 100    console.log(res.getNum())// 利用闭包函数修改 fn 函数内部的私有变量 num    res.setNum(200)// 当我再次利用 getNum 闭包函数去访问 fn 里面得 num 的时候    console.log(res.getNum())
复制代码

闭包的语法糖

        语法糖: 使用起来方便, 但是看起来不舒服

        闭包的语法糖: getter 获取器和 setter 设置器

        作用: 把你制作闭包想做的事情, 伪装成了一个对象内部的成员

使用方法:

        1. 要形成闭包

        2. 返回值是一个对象

        3. 在对象里面以 getter 和 setter 的语法形式返回函数

          {

            get 函数名() {},

            set 函数名() {}

          }

function fn() {      var num = 100      return {        getNum () {          return num        },        setNum (val) {          num = val        }      }    }    const res = fn()    console.log(res.getNum())    res.setNum(500)    console.log(res.getNum())
function fun() { var num = 100 return { get num() { return num }, set num(val) { num = val } } }// res 接收的还是 fun 里面返回的对象// 对象里面除了有 getNum 函数// 还把 getNum 作为一个成员存储起来了// 把 getNum 的返回值作为 getNum 这个成员的值使用// 把原先的 getNum 函数作为了获取器的存在// 对象里面会有一个 setNum 设置器// 当你给 setNum 设置器赋值的时候, 就是在调用 setNum 函数, 传递参数 const res2 = fun() console.log(res2.num) res2.num = 500 // 相当于原先的 res2.setNum(500) console.log(res2.num) console.log(res2)
复制代码


发布于: 刚刚阅读数: 3
用户头像

Jason199

关注

还未添加个人签名 2022.04.29 加入

一条努力上岸的咸鱼

评论

发布
暂无评论
闭包_js_Jason199_InfoQ写作社区