可用 proxy 拦截对象方法调用并自动添加防抖逻辑:get 拦截器识别函数属性,返回动态包装的防抖函数,支持 this 绑定、参数传递及定时器管理;增强版支持独立延迟、leading/trailing 配置与手动清理。

可以用 Proxy 拦截对象方法调用,在触发前自动套一层防抖逻辑,无需手动改写每个方法。
核心思路:拦截方法调用并动态包装
Proxy 的 get 拦截器能捕获属性读取。当读取的是函数时,不直接返回原函数,而是返回一个经过防抖处理的新函数。这样调用时实际执行的是防抖后的版本。
- 只对函数属性做处理,普通属性或非函数值照常返回
- 防抖函数需保存 timer,且每次调用前清除上一次定时器
- 要正确绑定
this和传入参数,避免丢失上下文
基础实现(支持单个方法)
下面是一个简洁可用的封装:
function debounceMethod(target, delay) {
const timers = new WeakMap();
return new Proxy(target, {
get(obj, prop) {
const value = obj[prop];
if (typeof value === 'function') {
return function(...args) {
const timerKey = `${prop}_${this === obj ? 'self' : 'other'}`;
if (timers.has(timerKey)) {
clearTimeout(timers.get(timerKey));
}
const timer = setTimeout(() => {
value.apply(this, args);
timers.delete(timerKey);
}, delay);
timers.set(timerKey, timer);
};
}
return value;
}
});
}
使用示例:
const api = {
fetchUser(id) { console.log('fetching user:', id); }
};
const debouncedApi = debounceMethod(api, 300);
debouncedApi.fetchUser(1); // 不立即执行
debouncedApi.fetchUser(2); // 清除前一个,300ms 后执行
debouncedApi.fetchUser(3); // 再次清除,300ms 后执行
增强版:支持配置与取消
更实用的版本应支持:独立 timer 管理、可取消、可选 leading / trailing、不同方法不同 delay:
function createDebouncedProxy(target, options = {}) {
const { delay = 300, leading = false, methods = {} } = options;
const timers = new WeakMap();
const getDelay = (method) => methods[method] ?? delay;
return new Proxy(target, {
get(obj, prop) {
const value = obj[prop];
if (typeof value !== 'function') return value;
return function debounced(...args) {
const ctx = this;
const fn = value;
const key = `${prop}_${ctx === obj ? 'bound' : 'unbound'}`;
const currentDelay = getDelay(prop);
if (timers.has(key)) {
clearTimeout(timers.get(key));
}
if (leading && !timers.has(key)) {
fn.apply(ctx, args);
}
const timer = setTimeout(() => {
if (!leading) fn.apply(ctx, args);
timers.delete(key);
}, currentDelay);
timers.set(key, timer);
};
},
// 可选:提供手动清理方法
apply() {
timers.forEach(clearTimeout);
timers.clear();
}
});
}
用法:
const service = {
save() { console.log('saved'); },
search(q) { console.log('search:', q); }
};
const proxied = createDebouncedProxy(service, {
delay: 200,
leading: true,
methods: { search: 500 } // search 单独设 500ms
});
proxied.save(); // 立即执行(leading),后续 200ms 内重复调用被忽略
proxied.search('a'); // 不立即执行,500ms 后执行
注意事项与边界情况
Proxy 防抖是运行时透明增强,但要注意:
- 不能代理箭头函数内部的 this:因为箭头函数不绑定 this,Proxy 无法修正;建议目标对象方法用普通函数声明
-
原函数引用会失效:比如
obj.method === proxied.method为 false,不能用于身份比对或事件移除 -
不适用于 setter / getter 属性:上面实现只处理函数,若需拦截 set 操作需额外加
set拦截器 - 内存管理:WeakMap 存 timer 已减少泄漏风险,但长期存活的代理对象仍需注意手动清理
不复杂但容易忽略细节。按需选用基础版或增强版即可。











