返回首页

关于--防抖节流及闭包

布莱克2026-03-02 16:19
Tip:文章封面与内容无关,作者旅游时拍摄,因为没什么值得把四季都错过!

防抖 (Debounce)

概念:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时

特点:只执行最后一次

手写防抖:

function debounce(fun, delay) {
      let timer = null;
      //args将调用函数时传入的所有参数收集为一个数组
      return function(...args) {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
          fun.apply(this, args)
        }, delay)
      }
    }

节流 (Throttle)

概念:规定在一个单位时间内,只能触发一次函数。

特点:按照固定频率执行。

手写节流:

//简化版,通过状态锁
    function throttle(fun, delay) {
      let run = true
      return function(...args) {
        if(!run){
          return
        }
        run = false
        setTimeout(() => {
          fun.apply(this, args)
          run = true
        }, delay)
      }
    }
场景防抖 (Debounce)节流 (Throttle)
搜索框输入 (联想查询)(等停顿再发请求)
窗口大小调整 (resize)(等调整完再计算)
表单验证(输完再校验)
滚动加载 (scroll)(每隔200ms判断位置)
点赞/抢购按钮 (防止连点)

关于防抖节流,必不可少的要讲到闭包

闭包

闭包允许一个函数访问并记住其外层作用域的变量,即使外层函数已经执行完毕

闭包的实现依赖于 JavaScript 的两个底层机制:

  1. 作用域链(Scope Chain):函数在声明时,会记录自己父级环境的引用。
  2. 垃圾回收与逃逸分析:正常情况下,函数执行完,栈内存(Stack)里的局部变量会销毁。但在闭包中,引擎发现内部函数引用了外部变量,会执行“逃逸分析”,将该变量从栈内存移动到**堆内存(Heap)**中,使其长久保存。

外部函数中返回了一个内部函数,内部函数引用了外部函数的变量,即使外部函数执行完,变量也不会被销毁,可以继续使用

闭包常用场景:

防抖(Debounce)与 节流(Throttle):利用闭包存储 timer 或 lastTime 标志位。

私有变量封装:模拟类的私有属性,防止外界直接修改内部状态(如:createCounter)。

函数柯里化(Currying):固定一部分参数,返回处理剩余参数的新函数

优点:

  • 数据安全:创建私有作用域,避免全局变量污染。
  • 逻辑封装:外部函数可以作为“工厂”,批量生产逻辑相同但状态独立的函数。
  • 状态持久化:让变量在函数执行结束后依然存在,不需要依赖不安全的全局变量。

缺点:

  • 内存压力:由于变量常驻堆内存,不被回收,过度使用会导致内存占用过高。
  • 内存泄露风险:如果闭包关联了大型 DOM 元素且未及时解除引用,可能导致内存泄露。
  • 性能微损:查找作用域链上的变量比访问局部变量稍微慢一点(但在现代引擎中可忽略不计)。
assistant