前言:
看千遍万遍,都不如自己手写一遍。
—鲁迅
代码:
①第一版
<body>
<input type="text">
<script>
var inp = document.querySelector('input')
var fn = function() {
console.log(“防抖”)
}
var debounce = function(fn,delay) {
var timer = null
return function() {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn()
}, delay);
}
}
inp.oninput = debounce(fn,1000)
</script>
</body>
思路:
该版本是测试,是否能正常执行防抖的打印输出,未考虑输出input框的输入值。
手写思路:
- 新建一个debounce函数,传函数参数和延迟delay参数; 函数中又返回一个匿名函数;
- 匿名函数中设置一个setTimeout定时器; 在定时器中执行传来的函数;
- 后面每次在规定delay时间内又触发debounce时,应该重新计时;
- 因为要重新计时就要清除定时器,为保证每次清除的timer都是同一个,
就在return外面定义timer(闭包); - 每次调用前判断timer是否有值,有就得先清除才能调用。
缺点:
因为目前只是测试能否执行防抖的逻辑,所以并未考虑input中的内容。又因为fn函数在setTimeout中是直接执行的,直接执行就会导致其this指向的是window,若这样的话我们就无法拿到我们输入的值。所以得改变this指向
①第二版
<body>
<input type="text">
<script>
fn = function (e) {
console.log(this.value)
console.log(e)
}
var inp = document.querySelector('input')
var debounce = function (fn, delay) {
var timer = null
return function (e) {//事件对象e
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this,arguments)
}, delay);
}
}
inp.oninput = debounce(fn, 1000)
</script>
</body>
思路:
该版本是完善版,该版本改变了this指向,因为该处使用了箭头函数,所以将this指向了父级作用域的执行上下文,即debounce中的this,其指向input元素,所以能拿到其输入的value。第二个参数arguments是传入事件对象,即上面的e
注意:
若不使用箭头函数无法将this正确指向inout元素,因为层级太深了,只能指向自己的指向上下文