防抖

35 阅读1分钟

防抖函数的基本实现

下面是一种常见的防抖函数写法:

const debounce = (fn, delay) => {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
};

为什么需要 clearTimeout(timer)

一个常见误解。设置 timer = null 并不会取消定时器,真正取消的是 clearTimeout(timer)
如果不手动清除,之前的定时器依然会在延迟后执行,造成不必要的多次调用。

this 丢失问题示例

有些防抖函数实现中,调用回调时省略了 applycall,直接使用了:

fn(...args)

这看起来简洁,但可能会导致 this 上下文丢失,在某些情况下引发 bug。

具体例子

const obj = {
  name: "Alice",
  sayName() {
    console.log("我的名字是", this.name);
  }
};

我们给 sayName 方法添加防抖:

const debounce1 = (func, delay) => {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func(...args); // ❌ 没有绑定 this
    }, delay);
  };
};

obj.sayNameDebounced = debounce1(obj.sayName, 500);
obj.sayNameDebounced();

预期输出

我的名字是 Alice

实际输出

我的名字是 undefined

原因分析

当我们执行 func(...args) 时,并没有指定 this
因此 sayName 中的 this 默认为 undefined(严格模式下)或 window(非严格模式下),而不是 obj

如何修复

使用 apply(this, args),显式传递 this