疑问求解:防抖函数的这个写法,重复触发后,timer 作为一个计时器被不停重置。但是我的理解是,在多次触发的时候 这个timer 与上一个 timer 是存在于同一个作用域内的吗?也就是此时的timer 与上一个timer 为什么会是同一个这个问题。可能是我钻牛角尖了,我错误的认为这个方法被触发的时候,是两个独立的作用域,但是我不理解为什么。
```javascript
var btn = document.getElementById('btn');
function debounce (fn, delay) {
let timer = null
return function () {
// 在规定时间内再次触发会先清除定时器后再重设定时器
console.log(timer)
clearTimeout(timer);
timer = setTimeout(function () {
console.log(this)
fn.apply(this, arguments);
}, delay);
}
}
function fn () {
console.log('防抖')
}
btn.onclick = function () {
debounce(fn, 3000)()
}
```
这个问题涉及到函数闭包的知识点。你可以看到,timer这个变量是在debounce函数中定义的,所以timer存在于debounce的作用域中,而我们调用的函数是debounce的返回值。正常情况下,debounce函数返回结果之后,它的生命周期就结束了,然后它的返回值当中包含着timer的引用,所以timer始终没有被垃圾回收掉,所以debounce函数的作用域也就一直存在,而无论调用多少次的onClick,它所用到的timer都是最开始debounce函数中的那个timer.
不知道你这个问题是否已经解决, 如果还没有解决的话:首先,防抖函数的作用是减少函数重复执行的次数,而不是让函数不被执行。防抖函数可以通过一个计时器来进行实现,例如在每次触发防抖函数时,先清除之前的计时器,然后重新设置一个新的计时器,当计时器时间到达时执行函数,这样可以保证函数只被执行一次。
当防抖函数被多次触发时,实际上每次触发都会执行一次该函数,但在函数内部使用的计时器是同一个,因为该计时器是使用闭包的方式保存在函数内部的。所以每次触发并不会创建一个新的作用域,而是在同一个作用域内执行,并且可以访问到上一次执行时创建的计时器,以此来达到防抖的效果。
下面是一个简单的防抖函数的实现及示例代码:
function debounce(func, delay) {
let timerId;
return function() {
clearTimeout(timerId);
timerId = setTimeout(() => {
func.apply(this, arguments);
}, delay);
}
}
function onInput() {
console.log('input event fired');
}
document.querySelector('input').addEventListener('input', debounce(onInput, 500));
上述代码中,防抖函数debounce
接收一个函数作为参数func
和一个时间间隔delay
,返回一个新的函数用于实际执行。在新函数内部使用clearTimeout
先清除之前的计时器,然后重新设置新的计时器,并在计时器时间到达时执行传入的函数。示例代码中,输入框的input
事件被包装成一个防抖函数,当连续多次输入时,只有最后一次输入会触发函数。