一、全局变量
1、在页面脚本<script></script>中直接用var关键字声明的变量称为全局变量,全局变量会作用于整个脚本,比如
<script>
var a=10;// a就是全局变量;而这个脚本就是它的作用域
</script>
2、还有一种情况,在函数内部不用var关键字声明的变量同样属于全局变量,比如
<script>
function cc(){
a=5;//这里的a不用var关键字声明,但也是全局变量。
}
</script>
二、局部变量
函数内部用var关键字声明的变量称为局部变量,局部变量的作用范围仅限于函数内部。比如
<script>
function dd(){
var a=3;// 这里的a就是局部变量,作用域仅限于当前函数内部。
}
</script>
该进入正题了。。。
三、闭包
当函数内部有对象能够保留函数内部数据时,我们称这个对象就是一个闭包。比如
function outer(){
var a=3;
function inner(){
alert(a);
a++;
}
return inner; //返回inner,好给外部变量引用;
}
var result=outer();//这个时候result就能让inner中的a值保留在内存中,产生了闭包,这个闭包就是inner,
result();//3
result();//4
result();//5
a的值会保留在inner中,这就是闭包的神奇而又强大的地方。
很可能很多人这个时候还是不明白什么是闭包,为什么会出现连加的情况,这就要讲一下作用域链的原理了。请看一下这个函数。
var n=3;
function Test(){
alert(n);
var n=4;
}
Test();
大家猜猜,运行的结果会是什么,很多人一下子就会说结果为:3;错!这时就又改变主意了,结果为:4;同样是错!正确的结果是:undefined,为什么会是这样呢,这就是函数作用域链的问题了,如果函数内部没有再次声明n的话,结果就是3,可惜函数内部声明了n,局部变量优先权高于全局变量,所以局部变量n会先放在作用域链的顶端,alert(a)要访问n值得从这个顶端进去查找,虽然作用域链中保存着n的指针,但还没给n赋值,所以会返回undefined。
理解了这个作用域链,我们就很容易理解闭包了。
又说回我们最开始的那个函数了,为了方便浏览,再次把它写在下面。
function outer(){
var a=3;
function inner(){
alert(a);
a++;
}
return inner; //返回inner,好给外部变量引用;
}
var result=outer();//这个时候result就能让inner中的a值保留在内存中,产生了闭包,这个闭包就是inner这个内部函数,它保留着a的值。
result();//3
result();//4
result()//5
其中inner就是闭包,也就是因为产生了闭包,它把每次调用result()后的a保留下来了,既然闭包(inner)中已经存在a,那为什么还要到父函数outer那里获取a值呢,现在已经没这个必要,因为inner中的a被保留下来,顺着作用域链,首先读取的是inner中保留着的a,而不会再去读取外层a 了,所以继续调用result的话a值会继续增加。
这个时候不知道我讲清楚没有,如果还不清楚的话请继续看下面一个函数,它只是outer函数的一个变形。
function outer(){
var a=3;
nAdd=function inner(){
alert(a);
a++;
}
}
outer();调用了outer函数,但产生了一个闭包,这个闭包同样是inner
nAdd();//3
nAdd();//4
nAdd();//5
那为什么outer没有寄存在外部变量中还可以产生闭包呢?不,outer虽然没有依赖外部变量,但在第一次的调用中却产生了一个全局变量,那就是nAdd,虽然outer没有寄存在nAdd上,但inner寄存了,由于nAdd是全局变量,它不会被浏览器的垃圾机制回收,所以inner中的数据也跟着保留下来。
最后,本文目的只为了让闭包更通俗易懂,描述的不专业也不严谨,就当做抛砖引玉吧。