就和上面两个例子中提到的一样。 主要是用到了三点
基础的html代码如下
const button = document.querySelector('#input')
function input () {
console.log('input!');
}
function debounce (fn,delay) {
// Todo: 完成防抖
}
button.addEventListener('click', debounce(input,1000))
function debounce (fn,delay) {
fn()
}
所以先改为高阶函数解决这个bug
function debounce (fn,delay) {
return function () {
fn()
}
}
为了形成闭包,这样在函数内部才能保证clearTimeout掉timer
function debounce (fn, delay) {
let timer
return function () {
clearTimeout(timer)
timer = setTimeout(function () {
fn()
}, delay)
}
}
在函数里面log一下this指针
const button = document.querySelector('#input')
function input () {
console.log('input!');
console.log(this);
}
function debounce (fn, delay) {
let timer
return function () {
clearTimeout(timer)
timer = setTimeout(function () {
fn()
}, delay)
}
}
button.addEventListener('click', debounce(input, 300))
结果函数内部的this指针变成了window,这是肯定不行的
function debounce (fn, delay) {
let timer
return function () {
let context = this
let args=arguments
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(context,args)
}, delay)
}
}
成功得到input的this指针
其实是可以用匿名函数来简化上面的代码的,但是只能简化setTimeout
里面的函数
function
里面的context上下文this
指针,所以return
的函数写成匿名函数会出错,代码如下function debounce (fn, delay) {
let timer
return () => {
let context = this
let args=arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context,args)
}, delay)
}
}
这种写法,this
指针会指向window
最终代码
function debounce (fn, delay) {
let timer
return function () {
let context = this
let args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, delay)
}
}
打过王者荣耀的都知道吧,拆塔的时候疯狂按攻击键?这没多大用
你的攻击次数由你的攻击速度(攻击间隔时长)决定
就是在上一次攻击指令完成前,是没有办法进行下一次攻击指令的
平A的僵直就是节流
在上面防抖基础上,节流的介绍就不再那么啰嗦,直接开始编写节流的代码
function throttle (fn, delay) {
let timer
return function () {
if (timer) return
timer = setTimeout(() => {
fn()
timer = null
}, delay)
}
}
1.2关键点还是改变this的指向
function throttle (fn, delay) {
let timer
return function () {
let context = this
let args = arguments
if (timer) return
timer = setTimeout(() => {
fn.apply(context, args)
timer = null
}, delay)
}
}
function throttle (fn, delay) {
let pre = 0
return function () {
let now = new Date()
let context = this
let args = arguments
if (now - pre > delay) {
fn.apply(context, args)
pre = now
}
}
}
2.2可以第一次不立即执行吗?可以!
判断,如果!pre就是第一次,第一次先拿到当前时间就可以了
function throttle (fn, delay) {
let pre = 0
return function () {
if (!pre) pre = new Date()
let now = new Date()
let context = this
let args = arguments
if (now - pre > delay) {
fn.apply(context, args)
pre = now
}
}
}
function throttle (fn, delay) {
let pre = 0
let timer
return function () {
if (!pre) pre = new Date()
let now = new Date()
let context = this
let args = arguments
let remainTime = delay - (now - pre)
if (now - pre > delay) {
fn.apply(context, args)
pre = now
} else {
if (timer) return
timer = setTimeout(() => {
fn.apply(context, args)
pre = now
timer = null
}, remainTime)
}
}
}