之前觉得已经掌握了函数防抖,今天看了一些大佬的文章,对防抖又有了新的了解,觉得自己之前掌握的只是一些皮毛,今天特此记录一下.
什么是防抖呢?根据个人的理解就是在用户某个操作下,高频触发了要执行的同一个函数,例如页面滚动,鼠标移入移出,快速点击按钮等触发函数事件。如果只是普通的函数方法还好,如果是函数中包含了ajax请求或者对dom的操作,都会加重浏览器负担,影响用户体验,所以函数防抖应运而生。所谓防抖,就是在函数高频触发下只执行一次,立即执行还是最后执行看网站需求。
非立即执行情况
举个最简单的例子,页面中有个按钮,点击后执行某个事件。
<input type="button" class="btn" value="点击">
var btn=document.querySelector(".btn");
//要执行的方法
function fun() {
console.log("方法执行了!");
}
基础版本:
btn.onclick=debounce(fun,500);
function debounce(fn, delay) {
var timer;
return function () {
clearTimeout(timer) ;
timer=setTimeout(()=>{
fn();
},delay)
}
}
通过js闭包的特性,将每次执行都要判断的timer保存下来,每次给timer赋值settimeout前先将定时器清除,在停止点击后的delay秒后执行。
进阶版本:
基础版本已经实现了我们想要的功能。但是如果当fun方法中用到了this,使用基础版本的话,this为window,因为settimeout是window下的方法。所以我们需要把当前的this保存下来,通过call或者apply方法来执行fun方法改变this指向。
function debounce(fn, delay) {
var timer;
return function () {
var _this=this;
//将当前的this指向保存下来
clearTimeout(timer) ;
timer=setTimeout(()=>{
fn.apply(_this);
},delay)
}
}
最终版本: JS的事件处理函数中会提供事件对象event,当fun方法需要event对象进行相关操作时,我们需要把这个参数传递过去。
function debounce(fn, delay) {
var timer;
return function () {
var _this = this;
//将当前的this指向保存下来
var arg=arguments;
//保存arguments对象将参数传给fn
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(_this,arg);
}, delay)
}
}
arguments是函数内部的一个类数组对象,而apply方法的第二个参数刚好可以传一个数组参数。
立即执行情况
立即执行情况的代码主要变化为判断timer来决定是执行函数还是清除定时器方法,首次执行后timer为假,此时立即执行fun方法,也就是我们想要的立即执行效果,然后给timer赋值定时器,执行timer=null方法,在之后的高频触发下,timer一直存在,只有当停止触发delay时间后timer=null,此时下次触发又会立即执行,由于别的代码变化不大,这里我们直接上最终版本代码。
最终版本:
function debounce(fn,delay){
var timer;
return function(){
var _this = this;
var arg = arguments;
timer ? clearTimeout(timer) : fn.apply(_this,arg);
timer=setTimeout(()=>{
clearTimeout(timer);
timer=null;
},delay)
}
}
结语:
第一次写文章语言逻辑什么的有些乱,主要就是想记录一下自己的所想所得。既然提到了防抖,那就不得不提节流,下篇文章我会记录一下我对节流的一些见解。