防抖是“最后一次触发后执行”,节流是“固定间隔内只执行一次”;二者均依赖闭包持久保存timer或lastTime等状态变量,确保跨调用共享与正确清除,否则无法实现防抖节流逻辑。

防抖和节流的核心区别在于执行逻辑:防抖等“最后一次触发停稳后再执行”,节流是“固定间隔内只执行一次”。而它们都必须用闭包,是因为要持久保存状态变量——比如定时器 ID、上一次执行时间、是否允许运行的标志位——这些变量不能在每次函数调用后就销毁,否则无法判断“该不该清掉旧任务”或“距上次执行过了多久”。
防抖为什么依赖闭包
防抖需要记住一个 timer 变量。每次触发事件时,都要先清除它再设新定时器。如果 timer 是局部变量,每次调用都会重新声明为 undefined;只有把它放在外层函数作用域中,由返回的内层函数持续引用,才能实现“跨多次调用共享同一个 timer”。这就是典型的闭包结构:内部函数使用了外部函数的变量,变量因此不会被垃圾回收。
- 没有闭包 → 每次调用都是全新 timer → 无法 clearTimeout 上一次任务 → 失去防抖效果
- 有闭包 → timer 被内层函数“捕获”并长期持有 → 可准确清除旧定时器,重置倒计时
节流为什么依赖闭包
节流要控制执行节奏,常见实现方式有两种:时间戳法或定时器法。无论哪种,都需要至少一个状态变量来记录关键信息:
- 时间戳法:需保存 lastTime(上一次执行时间),用于和当前时间比对是否超过间隔
- 定时器法:需保存 timer(当前延时任务),避免重复 setTimout,也便于在下次触发前清理
这些变量若不靠闭包维持,每次事件回调都是独立执行环境,无法感知历史状态,节流就退化成普通函数调用。
闭包在这里不是技巧,而是必要设计
防抖和节流本质上是“带记忆的函数工厂”:输入原函数和延迟参数,输出一个能自我管理执行时机的新函数。这个“记忆”能力只能由闭包提供。你写的 debounce(fn, 300) 返回的函数,之所以每次调用都能知道“上次设的 timer 是什么”,正是因为闭包把 timer 锁在了它的词法环境中。这不是为了炫技,而是机制运转的底层支撑。

















