一文教会你如何使用闭包,包教包会!

闭包:简单来说,就是为变量提供一个安全的、外部无法访问的作用域
本文:将通过一个累加器的案例帮助理解闭包

实现一个累加器

现在要做一个累加的功能。但是变量命名很容易重复,下面的代码不建议使用,因为变量很容易被别人定义,导致命名污染。

	  var count = 0
      function add() {
        return ++count
      }

在函数内部定义函数

使用函数嵌套函数的形式

	 function add() {
        var count = 0 // 私有变量,外界无法访问

        return function () { // 这是一个闭包函数 
             return ++count
        }
      }
	
	  // count是add返回的函数
      const count = add()

	  // 所以必须加括号才能得到count
      // 每次使用count()都会进行累加
      console.log(count()) // 1
      console.log(count()) // 2

	   // 注意这里如果使用两次add()都是得到1

设置形式参数

      function add(count = 0) {  // 如果不传默认为0
        return function () {
          return ++count
        }
      }

      const f = add(100)
      console.log(f()) // 101
      console.log(f()) // 102

进阶:以对象的形式返回

如果功能较多,建议采用模块化的形式以增加代码的维护性

function add(count) {
        return {
          add: function () {
            return ++count
          },
          double: function () {
            count *= 2
          },
          reset: function () {
            count = 0
          },
          print: function () {
            console.log(count)
          },
        }
      }

      const f = add(100)
      f.add()
      f.add()
      f.add()
      f.double()
      f.print() // 输出 206

闭包的场景(一般写法)

模拟查询和更新用户的消费积分的场景

      // 用户默认有50个积分,默认的权限等级为1,默认每次消费会增加5个积分
      function userInfoPoints(point = 50, roleLevel = 1, num = 5) {
        return {
          // 查询用户的当前积分
          get: function () {
            return point
          },
          // 每次增加num个积分
          add: function () {
            point += num
          },
          // 对当前的积分进行翻倍
          addDouble: function () {
            point *= 2
          },
          // 设置用户的当前积分
          setPoints: function () {
            // 如果达到管理员的权限等级
            // 实际项目中可能更复杂!!!
            if (roleLevel >= 5) {
              point = 500
              alert('积分设置成功')
            } else {
              alert('权限不足')
            }
          },
          // other
          otherFunction: function () {
            // 积分兑换活动...
          },
          // 输出
          print: function () {
            console.log(`当前消费积分的余额是:${point}`)
          },
        }
      }

      const user1 = userInfoPoints(100, 5, 5)
      user1.add()
      user1.add()
      user1.print() // 输出 110
      user1.setPoints()
      user1.print() // 输出 500

      // 再创建一个用户
      const user2 = userInfoPoints()
      user2.print() // 输出 50
      user2.add()
      user2.addDouble()
      user2.print() // 输出 110

      // 注意:这里的两个对象user1和user2并不影响,是完全独立的

运行结果如下
在这里插入图片描述
在这里插入图片描述

立即执行函数写法

;(function (w) {
        w.userInfoPoints = function (point = 50, roleLevel = 1, num = 5) {
          return {
            // 查询用户的当前积分
            get: function () {
              return point
            },
            // 每次增加num个积分
            add: function () {
              point += num
            },
            // 对当前的积分进行翻倍
            addDouble: function () {
              point *= 2
            },
            // 设置用户的当前积分
            setPoints: function () {
              // 如果达到管理员的权限等级
              // 实际项目中可能更复杂!!!
              if (roleLevel >= 5) {
                point = 500
                alert('积分设置成功')
              } else {
                alert('权限不足')
              }
            },
            // other
            otherFunction: function () {
              // 积分兑换活动...
            },
            // 输出
            print: function () {
              console.log(`当前消费积分的余额是:${point}`)
            },
          }
        }
      })(window, 100, 5, 10)

      const user1 = window.userInfoPoints(100, 5, 5)
      user1.add()
      user1.add()
      user1.print() // 输出 110
      user1.setPoints()
      user1.print() // 输出 500

      // 再创建一个用户
      const user2 = window.userInfoPoints()
      user2.print() // 输出 50
      user2.add()
      user2.addDouble()
      user2.print() // 输出 110

      // 注意:这里的两个对象user1和user2并不影响,是完全独立的

运行结果如下
在这里插入图片描述

总结

首先来看下MDN官方的描述

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

总结:在一个作用域中可以访问另一个函数内部的变量

作用:实现变量的私有化,从而避免全局变量的污染

特点

  1. 函数嵌套函数:闭包必须有函数嵌套函数的结构。
  2. 内部函数可以访问外部函数的变量:内部函数可以访问外部函数的变量,即使外部函数执行完毕后,这些变量仍可以被访问。
  3. 外部函数返回内部函数:外部函数必须返回内部函数,才能形成闭包。

注意事项

  1. 内存泄漏:闭包会一直持有外部作用域中的变量和参数,如果不及时释放,就会导致内存泄漏。
  2. 性能问题:由于闭包会持有外部作用域中的变量和参数,因此会占用更多的内存和 CPU 资源。
  3. 作用域链问题:由于闭包可以访问外部作用域中的变量和参数,因此会导致作用域链的变长,从而影响代码的执行效率。
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值