什么是闭包
概念:既重用变量又保护变量不被污染的一种编程方法。
运用:只要希望给一个函数,保存一个即可反复使用,又不会被外界污染的专属局部变量时,就用闭包。
如何使用闭包
- 用
外层函数包裹要保护的变量和使用变量的内层函数 - 在外层函数
内部返回内层函数对象。 调用外层函数用变量接住返回的内层函数对象。 举例:
//第1步: 用外层函数包裹要保护的变量和内层函数
function fun(){
var total= 1000
//第2步: 返回内层函数对象
return function(money){
// 来源于外部,进来之后可理解为自立门户了 。
// 既和外部产生了羁绊,有独立于外部。
total-=money;
console.log(`花了${money}还剩${total}元`)
}
}
//第3步: 调用外层函数,用变量接住内层函数对象
var pay= fun()
//pay接住的就是fun()返回出来的内层函数对象
pay(100); // 900
pay(100); // 800
total = 0;// 这里的total=0没有影响后边的total计算说明,total被保护起来,只能pay函数使用。
var payTwo= fun()
payTwo(100); // 900
payTwo(100); // 800
最内层函数,由内向外有三级作用域链:自己、外层函数的作用域、全局
解析:为什么形成闭包就可以保存变量不被释放
重点:所有函数调用完只清空作用域链中离自己近的一个作用域
释放的前提是:这个变量没有被引用,被垃圾回收器释放。
我们通俗的认为:程序执行完了之后,就被释放了。但在这边恰恰相反-由于return function(money){total -= moeny }里面引用了total所以不会被释放。
换句通俗易懂的话就是:因为fun函数的作用域对象被内层函数的作用域链引用着,无法释放,就侥幸存活下来!而且,只有内层函数pay知道total变量的存储位置——专属私密
强调:因为内层函数只是定义,未加()调用。所以,内层函数中的代码不执行!
解析:
()的作用:立即执行,通俗的理解来说是调用。你定义了一段代码片段,不去调用就没有(),想调用就有();
总结:到底什么是闭包
闭包就是每次调用外层函数时,临时创建的函数作用域对象。- 闭包也是一个对象。
- 为什么外层函数作用域对象能留下来?
- 因为被内层函数对象的作用域链引用着,无法释放。
闭包的缺点
由于闭包藏得很深几乎找不到所以,极容易造成内存泄漏!
解决:及时释放不用的闭包。
如何释放不用的闭包对象?
将保存内层函数对象的变量赋值为null;导致函数名变量与内层函数对象分开
pay= null
小练几题,理解闭包
题一:nadd函数立即执行
function fun1(){
var total= 1000;
// 最后添加的小括号,意思是:函数立即执行了。
nadd= function(){total++ ; console.log("-----",total)}() //1001
return function(money){
total-=money;
console.log(total)
}
}
var pay= fun1();
pay(100) // 901
pay(100) // 801
题二:调用nadd函数
function fun1(){
var total= 1000;
nadd= function(){total++ ; console.log("-----",total)}
return function(money){
total-=money;
console.log(total)
}
}
var pay= fun1();
pay(100) // 900
nadd() // 901
pay(100) // 801
题三:循环创建
function fun(){//妈妈
arr=[];//不算红包,因为内层函数中没有用到!
//但是arr是给未声明的变量强行赋值
//自动在全局创建该变量
for(var i=0/*红包*/;i<3;i++){//循环三次
//强行给外部全局变量中添加新函数——破腹产
// new Function()
arr[i]=function(){//反复创建了3个孩子
console.log(i);//因为只是创建函数,所以这里暂时不执行。
}
}
// for结束后,i=3
}
fun();
//妈妈一次刨妇产生了3个孩子,包了一个共用的红包,红包里是3块钱
//三个兄弟,输出的结果是一样的,都是3
arr[0]();//3
arr[1]();//3
arr[2]();//3
使用闭包实现防抖节流函数
节流函数
概念:一个函数执行一次后,只有大于设定的执行周期后才会执行第二次(有个需要频繁处罚函数,储于优化性能角度,在规定时间内,只让函数触发的第一次生效,后面不生效)
body,html{
height:200%;
}
functinon throttle(fn,time){
var lastTime = 0;
// 通过闭包来保存 lastTime 的状态
return function(){
var nowTime = Date.now();
if(nowTime - lastTime > time){
fn();
//同步时间
lastTime = nowTime;
}
}
}
document.onscroll= throttle(function(){
console.log('你触发了滚动事件')
},2000)
节流函数直观感受:
防抖函数
概念:一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效;
<button id="btn"></button>
function debounce(fn,delay){
var timer;
return function(){
clearTimeout(timer);
timer = setTimeout(()=>{
fn();
},delay)
}
}
document.getElementById('btn').onclick = debounce(function(){
console.log("点击事件被触发了 !")
},1000);
总结区别:
假如:对防抖函数和节流函数同时
不间断操作10秒,函数的时间间隔都为:2秒;
节流函数:会被触发五次;
防抖函数:只会被触发一次
出自东神(* ̄︶ ̄)!