一个简单的闭包例子
let 考试 = function(成绩){
let 要零花钱 = function(){
if(成绩===100){
return '妈妈给了100'
}else if(成绩>=90){
return '妈妈给了20'
}else{
return '妈妈很生气:"就这点分还想要零花钱?!"'
}
}
return 要零花钱
}
每次考试都会返回一个要零花钱的方法,考多少分给相应的钱
let 考试卷1 = 考试(99)
let 考试卷2 = 考试(88)
let 考试卷3 = 考试(100)
每考一次试会传入一个考试成绩,这个考试成绩会被考试卷保留
现在我们可以拿着这个试卷妈妈要零花钱啦(或者讨骂)!
考试卷1()
> '妈妈给了20'
考试卷2()
> '妈妈很生气:"就这点分还想要零花钱?!"'
考试卷3()
> '妈妈给了100'
这就是大名鼎鼎的闭包啦!
考卷1和它能访问的成绩99是一个闭包,
考卷2和它能访问的成绩88是一个闭包,
考卷3和它能访问的成绩100是一个闭包.
一个函数A(函数考试)可以创建多的数不清个自带环境的函数(生成多个考卷:考试卷1,考试卷2,考试卷3等等),
这数不清个函数都可以访问函数A为它专门创建的环境中的外部变量.(考卷可以访问成绩)
函数A生成的函数,和函数A为这个函数创建的环境的组合称为闭包.
注意:函数A并没有调用创建的函数(考试结束传入分数时并没有立刻要零花钱)
闭包有啥用?
我们把常用的东西放在一起,包在一个密闭空间内不被外界影响,方便稳定的组合体
闭包可以隐藏局部变量,暴露操作函数
1. 隐藏局部变量:
比如上面那个考试的例子和下面这个例子
let 三只松鼠零食 = function(某坚果){
let 坚果数 = 233
return function(){
console.log(`垃圾袋+湿巾+${某坚果}开壳器+${某坚果}${坚果数}粒`)
}
}
利用这一点可以创建出和多个和某个数据绑定的函数
2. 暴露操作函数
let 手机 = function() {
let 后台上限 = 4;
function 运行功能(val) {
一些让程序运行的代码(val)
后台上限--
}
return {
打开相机: function() {
运行功能(打开相机) ;
},
打开微信: function() {
运行功能(打开微信) ;
},
放歌: function() {
运行功能(放歌);
}
}
})
let 小王的手机 = 手机()
let 小李的手机 = 手机()
小王的手机.打开相机()
小李的手机.放歌()
利用这个方法,可以创建出很多有相同方法的函数
3. 帮助没有let的循环
如果不用闭包
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
> 6
> 6
> 6
> 6
> 6
> 6
这个例子会在控制台打出6个6,因为setTimeout是在for循环i加到6之后运行的,所以得到的i都是6.
但是如果利用闭包:
for (var i=1; i<=5; i++) {
(function() {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
})();
}
> 1
> 2
> 3
> 4
> 5
> 6
因为每次循环都形成了一个新的函数作用域,变量i的值被作用域记录下来,所以就会像我们脑补的那样,分别打出相加的数字了.
这个现在有let就不用啦,具体可以看闭包-JavaScript | MDN
闭包的缺点
- 会占用大量的内存空间:这是相对于原型链来讲的,
如果把需要重复使用的方法挂在原型上,就只要生成一次就可以了,
但是闭包每个对象都要生成一次 - 会造成内存泄漏
给自己挖个坑:函数可以限制调用次数么?考了一次试后可以限定要零花钱的次数么?