持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 12 天,点击查看活动详情
在面试中,我们经常会遇到需要手写代码的面试题,为了让我们的面试能够准备的更加充分,我们有必要好好的准备一下相关的手写题,正好就开了这个每日一题的专栏,旨在帮助大家熟悉场景的手写题。
今天我们就来学习面试中常见的一道手写题 -- 函数防抖
。
在写这个函数防抖之前,我们需要先了解它的定义,然后再一步一步分析该如何实现,而不是一上来就直接去死记硬背代码,这样就算你把代码都背下来了,但是在实际的开发中你还是不知道具体该如何使用。
防抖函数
debounce
指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次。实现原理就是利用定时器,函数第一次执行时设定一个定时器,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行。
有了上述关于函数防抖的描述,接下来我们就可以开始写代码了。首先我们定义一个 debounce
函数,这个命名也是约定俗成的,在这个函数中,我们会用到定时器 setTimeout
,然后再后续每次触发时,都需要先判断一下这个定时器是否已经存在了,如果存在则将定时器清空,我们来看代码,如下:
/*
* fn 要执行的函数
* wait 延时执行的时间,默认为300毫秒
*/
const debounce = (fn, wait = 300) => {
// 首先定义一个变量,用于存储定时器
let timer;
// 返回一个执行的函数
return function (...args) {
// 保存当前函数的this指向
const _self = this;
// 如果定时器已经存在了,则需要清除
if (timer) clearTimeout(timer);
// 重新执行当前的函数
timer = setTimeout(() => {
fn.apply(_self, args);
}, wait);
}
};
在上述代码中,我们根据前面的描述信息,一步步实现了这个函数防抖,下面我们来看一下在实际开发中是如何使用的,相关代码如下:
// 使用防抖函数包裹一个新的函数
const debounceFn = debounce(() => console.log('fn 防抖执行了'), 500);
// 绑定一个滚动事件
document.addEventListener('scroll', debounceFn);
在实际的开发中,当我们给 document
绑定一个 scroll
事件时,如果不添加函数防抖,则当我们在页面中执行滚动操作时,会持续的执行;而当我们加了一个函数防抖的效果后,则只有当我们停止滚动后,才会执行最后一次,这样做的好处是可以降低浏览器的频繁刷新。
接下来我们可以看一下业界比较有名的库 loadsh
中是如何实现 debounce
函数的,这里截取部分源码,如下所示:
function debounce(func, wait, options) {
...other code
function invokeFunc(time) {
const args = lastArgs;
const thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function startTimer(pendingFunc, wait) {
if (useRAF) {
root.cancelAnimationFrame(timerId);
return root.requestAnimationFrame(pendingFunc);
}
return setTimeout(pendingFunc, wait);
}
function cancelTimer(id) {
if (useRAF) {
return root.cancelAnimationFrame(id);
}
clearTimeout(id);
}
...other code
}
在 loadsh
的 debounce
源码中,我们也能看到它的实现中使用了 setTimeout
,而我们在面试中能够实现上面的那个方法即可,当然在实际的开发中,我们自己手写的 debounce
函数并不完善,因此我们也可以借助像 loadsh
这样比较有名的第三方库。
最后,大家要明白一点,面试是面试,工作是工作。