JavaScript的变量有两种,一种是局部变量,一种是全局变量。
顾名思义:
局部变量定义在函数内部,只能在函数内部访问,其他的函数无法访问;
全局变量则定义在函数外部,函数也可以访问外部变量;
二者的本质区别是变量的作用域不同——可见范围不同。
局部变量只在函数内部起作用,作用域是局部的,其他函数看不见
全局变量作用域是整体的,在JS程序中,处处可见
注意:如果在函数内部使用某个变量,却没用Var关键字定义,则其会被当做全局变量。
有些情况,需要在将函数的局部变量暴露出来……这就是闭包的价值所在。让我们逐步推演:
比如:
存在一个叫做计数器困境的问题:
我首先定义一个一个全局变量:
var total = 0;
然后定义一个函数:
function sum(){
total += 1;
}
后面我来调用sum函数,如:
sum();
sum();
调用了两次则,total的数值变成了?…………2!
看起来也不错呀
但是,问题出现了:整个total变量是全局的,是暴露给页面的所有脚本的,任何脚本都可能在有意或者无意之间,改变total的数值,从而导致total失效!
那怎么办?
我将total定义到函数内部吧!
如下:
function sum(){
var total = 0;
total += 1;
}
问题显而易见,也不行啊,每次调用sum,total都会被赋值0,无法计数!问题似乎更加严重了。
一计不成,再生一计!
要知道JS是支持函数的嵌套的,我们对上面的第一段码进行再次封装。
function sum(){
var total = 0;
function add() {
total +=1
}
add();
return total;
}
如此我们将变量限制到局部,算是解决了第一段代码的问题。但是,无法解决第二段代码的问题,total还是被多次执行!
我们的诉求是:第三段的代码中total只能执行一次!
终于,闭包来拯救我们咯!
上代码!
var sum = (function(){
var total = 0;
return function(){
return total += 1;
}
})();
这段代码解决了第二段代码的问题,及total被重复赋值的问题。
完美实现了:
计数器total为局部变量,只能通过sum方法去修改;
total计数时,不会被反复赋予初值;
内部计数函数能够访问上一级的total变量。
首先总结下:
闭包就是在一个函数的内部再定义一个函数,实现内部函数访问上一层函数作用域的变量!
再进一步:
函数a中定义了一个函数b,且在函数a外能够调用这个函数b,就会形成闭包。
那么,第四段代码该如何理解呢?
首先:Javascript的链式作用域访问逻辑,即子对象会向上一级别逐个去找变量,即所有上代的变量对于子代的对象都是可见的,反之则不行。
然后:我们分析代码:
var sum = (function(){
var total = 0;
return function(){
return total += 1;
}
})();
sum是一个变量,这个变量的值是自执行函数,重点是这个匿名的函数被小括号包起来,后面又加了一个小括号();这代表这个函数会被执行!即:新建了total变量,执行内部的函数返回一个表达式"total+=1",之所以没有返回表达式的计算结果:是因为内部函数没有自执行!
结果是sum = total+1;
再次调用sum(),sum被执行:结果为2
再次调用sum(),sum被执行:结果为3
……
为什么定义在函数内部的total没有被清除?因为total是sum变量表达式中的一个参数,它还有用!!
可见,这种方式实现了局部变量的常驻内存!对系统开销所有增加。建议不要滥用,在退出函数之前,将不使用的局部变量全部删除!
其实只要实现上述的目的代码都可以称为闭包
形式也是多种多样的。下面举几个例子:
额,我以为我会了,其实我没有。
闭包水太深,水性好的筒子,加油!我一个野生程序员,就先去练习肺活量了。