聊闭包,逃不过要说变量作用域
变量作用域
概念
一个变量可以使用的范围
看几个例子加深印象
- 例子1
var age = 20;
function fn(callback){
var age=18;
callback()
}
fn(function(){
console.log(this);//this指向window
console.log(age);//20
}
从上面例子看出,查找age变量的步骤:查找当前作用域;再查找上一级作用域(全局作用域),找到了
对于这个例子,为什么上一级作用域是全局作用域?而不是fn函数?因为,看上一级作用域,不是看函数在哪调用,而是函数写在哪。
- 例子2
function fn(){
var a=5;
return function(){
a++;
console.log(a);
}
}
var f1=fn(); //f1指向匿名函数
f1(); //6
f1(); //7
f1(); //8
看到上面代码的打印,为什么没有释放变量?一般函数执行完毕,变量会释放,但是js引擎发现匿名函数需要使用a变量,所以把a变量放到匿名函数可以访问到的地方了。显然,这是个闭包。
如果要释放a变量,要用 f1=null
作用域链
为什么要有作用域链
查找变量,上面第一个例子查找a变量,就是通过作用域链查找的。
查找变量步骤
- 查看当前作用域,若无,找上一级作用域。一直找下去,直到全局作用域。
闭包
闭包的概念
函数A内部有一个函数B,函数B可以访问到A中的变量,那么函数B就是一个闭包
闭包的意义
模块化、保护变量(我们只能间接访问函数内部的变量)
实际运用1
去一些餐厅,可能会有“最低消费”这一说法。我们用闭包模拟餐厅系统。
用自调用函数实现模块化,闭包保护变量leastPrice(需要查看外部访问者的权限),
var dining = (
function() {
var total = 0
var leastPrice = 30
return {
//计算买的总价
buy: function(price) {
total += price
},
//付钱
pay: function() {
if (total < leastPrice) {
console.log('请继续点餐');
return
}
console.log('点餐成功');
},
edit: function(id, val) {
//判断是否有权限
if (id == '888') {
leastPrice = val
}else{
console.log('权限不足')
}
}
}
}
)()
调式过程:
dining.buy(10)//买10块
dining.pay()//打印 请继续点餐
dining.buy(20)//再买20
dining.pay()//付钱 打印 点餐成功
dining.edit(888,10)//修改最低消费
dining.buy(12)
dining.pay()//打印 点餐成功
实际运用2
经典题,解决var变量定义函数的问题
for (var i = 1; i <= 5; i++) {
setTimeout(function() {
console.log(i)
}, i * 1000)
}
setTime异步函数,循环结束后,i=6,所以最后会每隔一秒打印6,并不是我们想要的 1 2 3 4 5
闭包解决:
for(var i=1;i<=5;i++){
;(function(j){
setTimeout(()=> {console.log(j)},j*1000)
})(i)
}
这样,打印的就是 1 2 3 4 5