前言
前两天面试 ,面试官问我闭包的应用场景,我没有回答出来,最近看了看,其中一个场景就是函数防抖节流。
开始实验
函数防抖是指在函数被高频触发时当停止触发后延时n秒再执行函数(即每次触发都清理延时函数再次开始计时),一般用于resize,scroll,mousemove等
现在我们来实现一个功能
在输入框中输入一个字符,先显示waiting ,延迟1秒后 在下方输出 这个字符,(就像百度搜索框 单机版) 如图
<input type="text" id="input"/>
<div id="show"></div>
<script>
function delay(e) {
let timeout;
timeout = setTimeout(()=>{
showInfo(e)
}, 1000);
}
document.getElementById('input').addEventListener('input',delay)
document.getElementById('input').addEventListener('input',function(){
document.getElementById('show').innerHTML='waiting'
})
</script>
如果没有使用防抖 就会像下面这样,多次调用就会添加多个settimeout到任务队列,1秒后执行,这样就会交叉显示了,当输入频率很快时就会这样。
(抖不抖???)
下面我们使用防抖技术
<input type="text" id="input"/>
<div id="show"></div>
<script>
function showInfo(text){
document.getElementById('show').innerHTML=text.target.value
}
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
document.getElementById('input').addEventListener('input',debounce(showInfo,1000))
document.getElementById('input').addEventListener('input',function(){
document.getElementById('show').innerHTML='waiting'
})
</script>
这样才算正常。(稳!!)
现在来说为什么要用闭包?
我们可以看到 在上面代码中 将timeout
变量变成全局变量也是可以实现的,如下代码。
<input type="text" id="input"/>
<div id="show"></div>
<script>
let timeout;
function delay(e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(()=>{
showInfo(e)
}, 1000);
}
document.getElementById('input').addEventListener('input',delay)
document.getElementById('input').addEventListener('input',function(){
document.getElementById('show').innerHTML='waiting'
})
</script>
因为这会出现如下问题:
1、对于一个页面上需要多个防抖函数的时候,需要写很多重复代码。
2、全局变量污染作用域
这时候闭包的优势就体现出来了,保护全局作用域不被污染,又能做到函数复用,我们只需要封装这么一个debounce函数就可以了:
function debounce(func, wait) {
/*
@ func 延迟执行的函数
@ wait 延迟时间
*/
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}