Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

函数防抖

核心原理:事件触发后等待一段时间,如果期间再次触发则重新计时,只执行最后一次。
很多人会疑惑“不使用闭包也能实现防抖吗?”,答案是“可以,但有明显缺陷”,以下对比 2 种非闭包写法与闭包写法的差异,说明为何闭包是最优解:

① 非闭包写法1:全局变量保存定时器(缺陷:污染全局作用域)
1
2
3
4
5
6
7
8
9
// 全局变量保存timer,污染全局作用域

let timer = null;
function debounce(fn, delay = 500) {
clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
}

问题:若页面中多个地方使用防抖(如两个输入框),会共用同一个timer,导致防抖逻辑混乱

② 非闭包写法2:局部变量保存定时器(缺陷:无法实现“重新计时”,防抖失效)
1
2
3
4
5
6
7
8
function debounce(fn, delay = 500) {
// 局部变量,每次调用debounce都会重新声明,无法获取上一次的timer
let timer = null;
clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
}

问题:每次触发防抖函数,timer都是新声明的null,clearTimeout无效,无法清除上一次的定时器,防抖失效

③ 闭包写法(最优解):局部变量通过闭包保存,既不污染全局,又能实现重新计时
1
2
3
4
5
6
7
8
9
function debounce(fn, delay = 500) {
let timer = null; // 闭包保存timer,仅在debounce第一次执行时声明1次
return function(...args) {
clearTimeout(timer); // 每次触发都能访问到同一个timer,清除上一次定时器
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}

优势:每个防抖实例都有独立的timer(闭包隔离),不污染全局,且能正常实现“重新计时”
总结:非闭包写法要么污染全局,要么防抖失效,而闭包通过“保存局部变量、隔离作用域”的特性,完美解决了这两个问题,这也是闭包在防抖/节流中不可替代的原因,也是面试中常考的“闭包实际应用”考点

评论