在 javascript 中,防抖(debounce)和节流(throttle)函数通过返回一个新的闭包函数来执行原逻辑,这导致新函数的 this 指向调用者而非原方法。要防止 this 丢失,核心做法是在包装函数内部使用 function.prototype.apply 或 function.prototype.call 显式绑定上下文,并将接收到的 this 和剩余参数传递给原始函数。

如何实现支持 this 的通用防抖函数
实现一个通用的防抖函数时,必须确保返回的函数能够透传 this 和 arguments。最稳健的方式是使用箭头函数包裹定时器逻辑,但在最终调用的那一层使用 apply。这样,当用户以 obj.method() 的形式调用时,this 会正确指向 obj。

function debounce(func, wait) {
let timeout;
return function(...args) {
const context = this;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
上述代码中,return function(...args) 定义了一个普通函数,它保留了动态的 this 绑定。在 setTimeout 回调中,我们使用 func.apply(context, args) 将当前作用域的 this(即调用者对象)传递给原函数。如果直接使用 func(...args),在非严格模式下 this 会指向全局对象,在严格模式下则为 undefined。
立即学习“Java免费学习笔记(深入)”;
如何实现支持 this 的通用节流函数
节流函数的实现通常涉及时间戳或定时器模式,同样需要处理 this 的传递。在时间戳模式中,我们需要在每次触发时立即执行并绑定上下文;在定时器模式中,需要在清除定时器后执行并绑定上下文。关键在于返回的函数签名必须能捕获当前的 this。

function throttle(func, interval) {
let lastTime = 0;
return function(...args) {
const context = this;
const now = Date.now();
if (now - lastTime > interval) {
lastTime = now;
func.apply(context, args);
}
};
}
在这个节流示例中,返回的函数同样使用了 ...args 来收集参数,并通过 const context = this 保存了调用时的上下文。随后调用 func.apply(context, args) 确保原函数在正确的上下文中运行。这种模式保证了无论节流函数被挂载在哪个对象上,其内部逻辑都能访问到该对象的属性和方法。
为什么箭头函数会导致 this 丢失以及如何避免
如果在防抖或节流的返回函数中直接使用箭头函数作为顶层返回,例如 return (...args) => { ... },虽然箭头函数本身没有自己的 this,它会捕获定义时的 this,但这通常不是我们想要的。因为防抖/节流函数通常在模块级别或构造函数外定义,此时 this 往往指向全局或 undefined。因此,返回的函数必须是普通函数,以便在调用时动态获取 this,然后在内部通过 apply 将其传递给目标函数。


















