函数防抖与节流依赖闭包保存timer等状态变量,确保多次触发时能清除旧定时器、重设新定时器,且各实例互不干扰;闭包还保障this和参数正确传递,但需注意内存滞留风险。

闭包让防抖和节流能记住“上一次的状态”
防抖和节流函数之所以能控制执行时机,核心在于它们返回的内部函数通过闭包持有了外部作用域中的变量(比如 timer)。这个变量不会随外层函数执行结束而销毁,而是被内部函数持续引用——这就实现了状态的跨调用保留。
timer 变量为什么必须在闭包里声明
在 debounce 和 throttle 的实现中,timer 都定义在外部函数作用域内,而非全局或事件回调内部。这样做的关键原因有:
- 每次调用
debounce(fn, 300)都生成独立的闭包,各自拥有自己的 timer,互不干扰 - timer 存在闭包中,使得后续多次触发事件时,内部函数总能访问并操作同一个定时器引用
- 若把 timer 放到全局,多个防抖实例会互相覆盖;若放在事件回调里,则每次都是新变量,无法清除前一个定时器
作用域链如何支撑 this 和参数的正确传递
闭包不仅保存了 timer,还让内部函数能沿作用域链访问到外层传入的 func、delay 等参数。更重要的是,当使用 func.apply(this, args) 时:
- this 来自事件触发上下文(比如 input 元素),不是闭包外层的 this
- args 是调用时传入的实参,闭包本身不捕获它,而是靠返回函数接收并透传
- 如果直接写
func(),this 会丢失(指向全局或 undefined),导致目标函数内部逻辑出错
闭包带来的内存影响需要留意
闭包让变量长期驻留内存,这是功能所需,但也需清醒认识:
- 只要返回的防抖/节流函数还在被引用(如绑定在 DOM 事件上),其闭包环境就不会被回收
- 组件卸载或监听器移除后,应主动解除引用(如设为 null),避免意外的内存滞留
- 不需要手动清理 timer,但要确保没有无意义的长期闭包持有(例如在循环中反复创建未销毁的防抖函数)











