1.什么是闭包?
闭包是这样的一种机制:函数嵌套函数,内部函数可以引用外部函数的参数和变量。参数和变量不会被垃圾回收机制收回。
一个经典的闭包:
function fn() {
let a = 1;
return function () {
a++;
return a;
}
}
let newFn = fn();
console.log(newFn());
console.log(newFn());
console.log(newFn());
闭包的原理
1.垃圾回收机制 ---- .标记清除法 ---- .引用计数法
被外部引用的局部变量没有被回收。
(1.标记清除法):js会对变量做一个标记yes or no的标签以供js引擎来处理,当变量在某个环境下被使用则标记为yes,当超出改环境(可以理解为超出作用域)则标记为no,然后对有no的标签进行释放。
(2.引用计数法):对于js中引用类型的变量, 采用引用计数的内存回收机制,当一个引用类型的变量赋值给另一个变量时, 引用计数会+1, 而当其中有一个变量不再等于值时,引用计数会-1, 如果引用计数为0, 则js引擎会将其释放掉。
2.作用域链
内部函数使用变量的时候,会现在自身寻找,找不到回去父级作用域中找,如果没找到会返回undefinde
二.闭包的作用是什么?
闭包特点:
1.让外部访问函数内部变量变成可能
2.变量会常驻在内存中
3.可以避免使用全局变量,防止全局变量污染
闭包的好处:
1.可以让一个变量长期在内存中不被释放
2.避免全局变量的污染,和全局变量不同,闭包中的变量无法被外部使用
3.私有成员的存在,无法被外部调用,只能直接内部调用
闭包的缺点:
1.当前变量会一直保存,容易造成内存泄漏
解决:变量不在引用需要手动赋值为null
解决了两件事情:
1.读取及操作外部函数的私有变量。
2.使得外部函数的私有变量不会被清除,一直存在内存中
三.闭包可以完成的应用:1.防抖.2.节流3.函数柯里化
1.防抖
//防抖 避免函数的重复调用 只会调用一次
function Antishake(fn,wait){ //第一个参数是函数 第二个参数是毫秒值
let timer = null //声明一个变量来接收延时器 初始值为null
return function(){
clearTimeout(timer)
timer = setTimeout(() => {
fn() //调用这函数
}, wait);
}
}
let an = Antishake(function(){ //用一个变量接收
console.log('555');
},2000)
document.querySelector('div').onmouseenter = ()=>{
an() //调用一次
}
2.节流
function throttle(fn,wait){
let timer = null //节点闸
return function(){
if(timer) return
//null false 不是null结果减少true 如果上传没有我就直接跳过 没有人我就上去
timer = setTimeout(() => { //上车了
fn()
timer = null //做完之后重新关闭节点闸
}, wait);
}
}
let throttle1 = throttle(()=>{
console.log('我上车了');
},2000)
document.querySelector('div').onclick = ()=>{
throttle1()
}
防抖和节流的区别
防止函数短时间内被多次触发,希望抖动结束只执行一次
节流 减少执行的次数,执行多次。控制短时间的执行次数
3.函数柯里化
把多参数的函数,转为 一个参数的函数
函数柯里化 其实就是函数颗粒化 将一个函数变成一个个颗粒可以组装,就是这个里面的多个参数 将他变成一个个的函数来传递这个参数。
简单柯里化函数:
fuunction sum(a){
return function(b){
return a+b
}
}
let fn = sum(1);
let r = fn(2);
console。log(r)