一、闭包有三个必要的条件
1.函数A内部直接或者间接返回一个函数B。
2.函数B内部使用着函数A的私有变量(就是函数A的私有数据)。
3.函数A外部有一个变量接受着函数B。
以上三个条件便形成了一个不会销毁的函数空间,这个函数空间也就叫做闭包空间,把函数A里面返回的函数B,叫做闭包函数,所以闭包也就是函数内部的函数
function a(){
let num = 100;//这是函数A的私有变量
return function b(){
console.log(num)//这里在返回的函数B中使用了函数A的私有变量
}
}
let res = a()//让函数A的返回值给变量res,也就是把函数B给res
res()//此时执行res 得到的就是函数A里面私有变量num的值
二.闭包的特点(优缺点并存)
1.延长了变量的生命周期
优点:因为执行空间没有被销毁,所以变量也一直存在。
缺点:因为执行空间没有被销毁,会一直存在在内存当中。
2.可以访问到函数内部的私有变量
优点:可以利用闭包函数访问到函数内部的私有变量。
缺点:因为执行空间不会销毁,所以要占用内存。
3.保护函数私有变量
优点:保护私有变量不被外界访问。
缺点:要想访问函数私有变量就必须要用闭包
注:因为使用闭包函数会使函数的执行空间一直存在,所以一旦使用过多存在的执行空间就越多,导致内存占用过多发生内存溢出,结果就内存泄露了 。
三.直接返回和间接返回
直接返回:就是直接return一个函数
间接返回:return的值不是一个函数,是一个对象或者一个数组
function fn(){
let num = 100;
let num1 = 200;
return {//返回一个对象
getNum:function(){
console.log(num)
},
getNum1:function(){
console.log(num1)
}
}
}
let res = fn()
//下面调用对象里面的属性
res.getNum()//得到num的值
res.getNum1()//得到num1的值
闭包的应用
在es6以前没有let定义变量 也就没有块级作用域
当使用循环的时候用var定义
//假设页面上有五个按钮
var oBtns = document.querySelectorAll('button')
for(var i = 0 ;i<oBtns.length;i++){
oBtns[i].onclick = function(){
console.log(i)
}
}
//此时不论点击那个按钮 打印的i值都是4 因为循环第一遍i=0 循环后执行空间销毁
一直到i=4,所以执行后只剩下i = 4
所以利用闭包空间来解决
把点击事件封装为一个loop函数
function loop(num){
oBtns[num].onclick = function(){
console.log(num)
}
}
for(var i = 0;i<oBtns.length;i++){
loop(i)
}
//此时点击的那个按钮就打印那个按钮的索引
这就是利用闭包的特点不会销毁执行空间因此前面的循环的i值没有销毁