一、原理:
-
防抖函数用于确保在某个连续触发的事件结束后,监听该事件的回调函数在事件无触发n秒之后才执行一次
-
这对于处理用户输入、窗口大小调整等频繁触发的事件很有用
-
可见,debounce函数控制回调函数执行的频率,那么debounce函数的返回值应该是一个函数。
参数有两个1.获取到的回调函数 2. 设置的规定时间
二、代码实现
function debounce(callback,delay){
let timerId = null; // 用于保存定时器的ID
function _debounce(...args){
if(timerId) clearTimeout(timerId) // 取消上一个定时器
// 等待delay后,将监听事件的回调函数放入宏任务队列中
timerId = setTimeout(()=>{
callback.apply(this,args);
},delay)
}
return _debounce;
}
// 用防抖函数debounce将原先绑定给事件的函数包裹一下,这样的话,就能实现图中的功能了
const debounceFn = debounce(fn,2000)
debounceFn("hello",123)
1. 解决回调函数的this指向问题
当你使用DOM事件监听器时,事件回调函数内的this默认指向触发事件的 DOM 元素。这是因为事件处理函数会在元素上下文中执行
- 回调函数是箭头函数形式: 指向外部的作用域的this
- 回调函数是普通函数形式: 内部的 this 不会指向触发事件的DOM 元素
<body>
<button class="btn"></div>
</body>
<script>
const btn = document.querySelector(".btn")
// btn.addEventListener("click",()=>{})
btn.addEventListener("click",fn)
}
</script>
解决方法:
调用debounce函数最终返回_debounce函数,相当于监听事件的回调函数是_debounce,因此_debounce函数的this一定指向DOM元素,因此我们在_debounce函数内执行callback时,使得callback的this与_debounce函数一样即可(否则callback的this指向就会根据执行环境而变化)
- 要么将定时器内部的函数,写成箭头函数形式
function debounce(func,delay){
var timer = null;
function _debounce(){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
func.apply(this)
/*
箭头函数内部的this在定义时就确定了,与外部非箭头函数的this指向一致
这里的外部非箭头函数 === _debounce函数
*/
},delay)
}
return _debounce;
}
- 要么将定时器内部的函数,写成普通函数,但是用变量_this保存_debounce函数的this指向
function debounce(func,delay){
var timer = null;
function _debounce(){
var _this = this; // 用 _this 记录当前的this
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(_this);
},delay)
}
return _debounce;
}