目录
一、定义
闭包的生成有三个必要条件,缺一不可
- 在A函数内直接或间接返回一个函数B;
- B函数可以使用A函数的私有变量;
- 在A函数外有一个变量来接收B函数
这样,就形成了一个不会销毁的函数空间。
我们管这个不会销毁的A函数的执行空间叫做 闭包
把函数A里面返回的函数B,叫做 函数A的闭包函数
二、一个简单的闭包例子
function a(){
let num = 100
return function b(){
console.log(num)
}
}
let res = a()
console.log(res)
res()
从现在开始 res随时可以被调用
在我们的执行空间里 函数a里面的一切都不会被销毁
(这是一个直接返回函数的例子)
三、直接或间接返回一个函数
直接返回一个函数 return function(){}
间接返回一个函数 return 一个对象或数组 (这个对象或数组里面有多个数组)
使用场景:
- 当我只需要访问一个私有变量的时候可以使用直接或间接
- 当我访问多个私有变量的时候,我们需要使用间接返回的方式
// 一个间接返回函数的例子
function fn(){
let num = 100
let num2 = 200
return {
getNum:function(){
console.log(num)
},
getNum2:function(){
console.log(num2)
}
}
}
// 闭包
let res = fn()
console.log(res)
res.getNum()
四、闭包的特点(优点与缺点并存)
优点:可以延长变量的生命周期,因为执行空间不会被销毁,所以变量也不会被销毁。
可以利用闭包函数访问函数内部的私有变量。
缺点:因为执行空间不会被销毁,所以变量一直存在内存中,过多占用内存,就会导致内存溢出
因此,就是当需要延长变量的生命周期的时候或者需要访问某一个函数内部的私有变量的时候,我就可以使用闭包来解决问题。在实际应用中,闭包经常被用于封装私有变量、缓存计算结果、解决异步回调等问题。但是过度使用闭包可能会导致内存泄漏和性能问题,因此需要谨慎使用。前提是如果有别的办法,优先使用别的方法,没有别的方法了,就使用闭包。
五、销毁闭包
function a(){
let num = 100
return function b(){
console.log(num)
}
}
let res = a()
// 释放空间(销毁闭包)
res = null
六、柯里化函数
柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用
function printInfo1(xueke,banji,name,age){
console.log(`${xueke} ${banji} ${name} ${age}`)
}
printInfo1('计算机','前端','小李',17)
printInfo1('计算机','前端','小敏',19)
printInfo1('计算机','前端','小丽',17)
改写上面的不好用函数
对于学科和班级都是一样的,我觉得没必要再作为参数传递了
写一个闭包
function printInfo(xueke,banji){
return function(name,age){
console.log(`${xueke} ${banji} ${name} ${age}`)
}
}
// 生产出一个固定学科和班级的函数
let print2020 = printInfo('计算机','前端')
// 开辟了一个printInfo空间 xxff11
// 在这个空间里面进行形参的赋值
// let xueke = 计算机
// let banji = 前端
// 定义函数 function(name,age){}
// 把执行空间里面定义的这个函数地址xxff1122 赋值给print2020
print2020('小李',17)
print2020('小敏',19)
print2020('小丽',17)
上述两个函数打印结果一致。
七、使用闭包模拟私有方法
在JavaScript
中,没有支持声明私有变量,但我们可以使用闭包来模拟私有方法
下面举个例子:
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */
上述通过使用闭包来定义公共函数,并令其可以访问私有函数和变量,这种方式也叫模块方式。
两个计数器 Counter1
和 Counter2
是维护它们各自的独立性的,每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境,不会影响另一个闭包中的变量。