1.什么是闭包?
闭包就是内部函数对外部函数变量的引用。
可以简单理解为:闭包=内层函数+引用外层函数变量。
2.闭包的注意点:闭包一定有return?闭包一定会内存泄漏?不一定
当我们想要访问闭包内部的变量时,就可以使用return,将内部函数作为返回值。
function count() {
let num=0;
return function fun(){
num++
console.log(`函数被调用${num}次`);
}
}
let res=count();//变成全局变量不会被垃圾回收机制回收会引起内存泄漏
res();//调用一次
res();//调用两次
谁会存在内存泄漏? count变量
借助于垃圾回收机制的标记清除法可以看出∶
①: res是一个全局变量,代码执行完毕不会立即销毁。②: res使用count函数③: count用到fun函数。④: fun函数里面用到count。⑤: count被引用就不会被回收,所以一直存在。
此时:闭包引起了内存泄漏
3.闭包的作用?
①避免变量被污染,②变量私有化,③保存变量,常驻内存
4.闭包的使用场景
a.防抖 (高频率触发的事件,在指定的单位时间内,只响应最后一次,如果在指定的时间内再次触发,则重新计算时间 防抖类似于英雄联盟回城6秒,如果回城中被打断,再次回城需要再等6秒)
①.search搜索联想,用户在不断输入值时,用防抖来节约请求资源
②.window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
function debounce(fn, delay){
let timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(()=> {
fn.apply(this, arguments);
}, delay)
}
}
b.节流(高频率触发的事件,在指定的单位时间内,只响应第一次
节流类似于英雄联盟里的英雄平A 一定是内点击多次只进行攻击一次)
①.鼠标不断点击触发,mousedown(单位时间内只触发一次)
②.监听滚动事件,比如是否滑到底部自动加载更多
function throttle(fn, delay){
let valid = true;
return function(){
if(valid) { //如果阀门已经打开,就继续往下
setTimeout(()=> {
fn.apply(this, arguments);//定时器结束后执行
valid = true;//执行完成后打开阀门
}, delay)
valid = false;//关闭阀门
}
}
}
// 刚开始valid为true,然后将valid重置为false,进入了定时器,在定时器的时间期限之后,才会将valid重置为true,valid为true之后,之后的点击才会生效
// 在定时器的时间期限内,valid还没有重置为true,会一直进入return,就实现了在N秒内多次点击只会执行一次的效果
//用法:
function fn(value){
console.log(value);
}
var throttleFunc = throttle(fn,2000);//节流函数
//事件处理函数,按钮点击事件
btn.addEventListener("click",function(){
throttleFunc(Math.random());// 给节流函数传参
})
c.定时间setTimeout 传递的第一个函数不能带参数,通过闭包可以实现传参效果。
function f1(a) {
function f2() {
console.log(a);
}
return f2;
}
var fun = f1(1);
setTimeout(fun,1000);//一秒之后打印出1
d.用于公共方法或者包的封装,比如数据响应式原理,axios二次封装等。