什么是闭包? (有代码有讲解)

我们要是想知道什么是闭包?就要从以下方法中寻找,想必大家已经迫不及待了吧!!!!

我们在学习中想要学习一个知识,怎么证明学会了呢?

就要了解这个知识点是什么?怎么用?解决了什么问题?原理是什么?等等。

闭包是什么(闭包的概念)?

在《JavaScript高级程设计》说到 : 闭包(closure)指有权访问另一个函数作用域中变量的函数

我个人觉得,【一个函数】使用了其【外部函数】中的局部变量,使用变量的地方我们称之为发生了【闭包现象】,变量定义所在的函数我们称为【闭包函数】。

讲到这里,可能还是有一些同学不太了解,没关系,我们来举个例子:

  • 举例: js函数A里面有一个函数B,函数B访问了函数A里面定义的局部变量,此时就产生了闭包,变量所在的函数就是闭包函数。这里的A就是闭包函数。
function fn() {
  let age = 18
  return function () {
    // 在这里打断点(debugger)可以看到 closure(fn) // 如果外层是匿名函数 就只会看到closure
    console.log(age + 1)
  }
}
const sum = fn()
sum()
闭包的作用?

解决全局变量污染,延长作用域

我们可以从闭包的作用中又可以了解到延伸了变量的作用范围,闭包函数中局部变量不会等着闭包函数执行完就销毁,而是等所有的函数都调用完才会销毁,导致内存泄露,内存泄露积累多了就容易导致内存溢出。

什么是内存泄露?我们也来了解一下。

内存泄露也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕之后未释放,结果导致一直占据该内存单元,直到程序结束----------即所谓内存泄露

其实说白了就是该内存空间使用之后没有及时回收。

哪些操作会导致内存泄露?

1.垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为0(没有其他对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存即可回收。

2.setTimeout的第一个参数使用字符串而非函数的话,会引发内存泄漏。

3.不规范使用闭包、控制台日志、循环

防止内存泄漏的方法
1.减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收(即赋值为null);

2.注意程序逻辑,避免“死循环”之类的;

3.避免创建过多的对象 原则: 不用了的东西要记得及时归还;

4.减少层级过多的引用

如何判断闭包

代码角度:函数 + 上下文引用

控制台角度: 会提示closure

闭包有两个常用的用途:
  • 使我们在函数外部能够访问到函数内部的变量。通过使用闭包,可以通过在外部调用闭包函数,从而在外部访问到函数内部的变量,可以使用这种方法来创建私有变量。
  • 使已经运行结束的函数上下文中的变量对象继续留在内存中,因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收

在开发中哪些地方会使用到闭包?
  • 一般封装防抖函数的时候也会用到。
<!--给一组按钮循环绑定点击事件,点击的时候希望输出对应的索引。 -->

<!-- 其实是做不到的,因为当点击按钮的时候,for 循环早就走完了,i 也就变成了最终的那个数值,输出的结果也永远是最终的那个数值。 -->
<body>
  <button>1</button>
  <button>2</button>
  <button>3</button>
  <button>4</button>
  <button>5</button>
  <script>
    const Btn = document.querySelectorAll('button')
    for (let i = 0; i < Btn.length; i++) {
      Btn[i].onclick = function () {
        console.log(i)
      }
    }
  </script>
</body>
  • 比如说,在早期,给一组按钮循环绑定点击事件,点击的时候期望输出对应的索引,本质上是做不到的,因为当点击按钮的时候,for循环早就走完了,i也变成了最终的那个数值,输出的结果也永远是最终的那个数值,这个时候可以每次循环都产生一个闭包函数,并把循环时候的变量i传递过去,这个循环时候的就会常驻内存,就做到了内
    部使用的i就是循环时候那一刻的i
<body>
  <button>1</button>
  <button>2</button>
  <button>3</button>
  <button>4</button>
  <button>5</button>
  <script>
    const Btn = document.querySelectorAll('button')
    for (let i = 0; i < Btn.length; i++) {
      (function (i) {
        // 【函数形参 i 也是局部变量】
        Btn[i].onclick = function () {
          console.log(i)
        }
      })(i)
    }
  </script>
</body>

应用?

  • 函数防抖
 function debounce(fn, delay) {
  let handle;
  return function (e) {
  // 取消之前的延时调用
  clearTimeout(handle);
  handle = setTimeout(() => {
  fn(e);
  }, delay);
  }
 ​
 }
  • 函数节流
 function throttle(fn, delay) {
  let runFlag = false;
  return function (e) {
  // 判断之前的调用是否完成
  if (runFlag) {
  return false;
  }
  runFlag = true;
  setTimeout(() => {
  fn(e);
  runFlag = false;
  }, delay)
  }
 }
  • 变量持久化 (闭包中的变量不会被回收)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值