1. 防抖
从概念上来讲,所谓的闭包指的是一个函数,有权访问另一个函数作用域中的变量的函数。
直观点来讲,JavaScript的闭包就是函数中嵌套函数。
<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变量变成全局变量来实现闭包?能
缺点:
1、对于一个页面上需要多个防抖函数的时候,需要写很多重复代码。
2、全局变量污染作用域
<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>
- 问题二:可以在函数内定义一个timeout,然后当函数执行时清除,实现防抖吗?不能
每次事件触发后,都创建一个函数作用域内的timer变量,这样每次创建的timer变量相互不影响,且每次timer都是从undefined开始,也就不会执行clearTimeout(timer)了,不能达到防抖的目的。
本质上来讲,是因为作用域而产生一种特殊的情况,从而导致函数内部的变量无法进行销毁。这里涉及到作用域链。也是闭包产生的根本原因。
下面补充一下作用域链(Scope Chain)的知识:
从1->0
a执行完毕之后,函数链会断开,但是b执行仍然会链接上a中的变量,所以可以访问到
var global;
function a(){
var a=123;
function b(){
var bb=234;
console.log(aa);
}
return b;
}
var res=a();
res();
参考链接:作用域链
- 总结
1、把timer变量放在内部函数中不能达到防抖的目的,因为每次执行内部的函数,都会创建一个新的timer变量。
2、用立即执行函数创造闭包可以实现防抖,是因为每次执行内部的函数,都是在操作同一个timer变量,由外部立即执行函数创建的timer变量。
3、闭包多是结合立即执行函数一起使用的,有时可能立即执行函数没有那么明显。
4、将变量timer定义为全局变量也可以达到防抖的目的,但是闭包有2个优势-
5、不用担心全局变量污染问题
6、多次调用时,相互不影响。而声明全局变量时,每次要声明不同的名字,才能不相互影响。