在面试中会经常问到有关js的闭包的知识,其中,防抖节流函数是闭包的经典应用,在谈到防抖节流函数之前先引出闭包。
闭包
闭包的本质就是在一个函数内部创建另一个函数。
闭包的特性
- 函数嵌套函数;
- 函数内部可以引用到函数外部的参数和变量;
- 参数和变量不会被垃圾回收机制回收。
闭包形成的原因
外层函数的函数作用域对象,因为被内层函数作用域链引用这无法释放,就成了闭包
闭包的好处与坏处
好处:
- 保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
- 在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
- 匿名自执行函数可以减少内存消耗
坏处:
- 其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
- 其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。
防抖函数
当持续触发事件,一定时间内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
let timer
clearInterval(timer)
timer = setTimeout(function(){
...
},delay)
实际的应用
使用echarts时,改变浏览器宽度的时候,希望重新渲染
echarts的图像,可以使用此函数,提升性能。(虽然echarts里有自带的resize函数)
典型的案例就是输入搜索:输入结束后n秒才进行搜索请求,n秒内又输入的内容,就重新计时。
解决搜索的bug
<body>
<input type="text" id="input">
<script>
function debounce(callback, delay) {
let timer;
return function(arg) {
clearTimeout(timer)
timer = setTimeout(function () {
callback(arg);
}, delay)
}
}
function func(value) {
console.log(value);
}
var input = document.getElementById('input');
var debounceFn = debounce(func, 1000)
input.addEventListener('keyup', function(e) {
debounceFn(e.target.value)
})
</script>
</body>
第一次输入1,隔一段时间输出,可以自己试试…
节流函数
当持续触发事件的时候,保证一段时间内,只调用一次事件处理函数,一段时间内,只做一件事情。
实际应用
表单提交
典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效。
<body>
<button id="button">点击</button>
<script>
function throttle(func, wait) {
let timeOut;
return function () {
if(!timeOut) {
timeOut = setTimeout(function() {
timeOut = null;
func();
}, wait)
}
}
}
function handle() {
console.log(Math.random());
}
document.getElementById("button").onclick = throttle(handle, 2000)
</script>
</body>
一段时间内(2000)点击只打印一次随机数…
如有问题,欢迎纠正…