来看一个比较简单的例子:
function fun () {
var a = 0;
function add () {
a++;
console.log(a);
}
return add
}
var test = fun();
test();
test();
这个例子中,函数fun里面嵌套了另外一个函数add。当执行test = fun()语句的时候,也就是函数fun执行完毕时,test其实就是函数add,并且是全局的。
当执行test()的时候,fun()函数里面的局部变量a就会被调用++操作,所以console.log(a)会输出1;再次执行test()的时候,a在等于1的基础上再加1,这时候console.log(a)的话会输出2。
再来看一个例子:
function fun(n,o) {
console.log(o);
return {
fun:function(m) {
return fun(m,n);
}
};
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1); c.fun(2); c.fun(3);
首先来分析一下代码,第一行:最先执行的是a = fun(0);也就是说传入参数 [0, undefined]给外层的fun函数,所以console.log(o)是输出undefined。因为前面参数n的实参为0,所以此时在内存中n的值为0;
然后执行a.fun(1),也就是说执行嵌套的fun函数,此时m的实参是1;那么外层函数(嵌套函数fun里面return的fun就是外层函数)的参数就变成了fun(1, 0),所以这时候console.log(o)的话输出的是0。同时在内存中n的值变成了1。
执行a.fun(2),结果是一样的,只是n在内存中的值变成了2,o还是等于0;
执行a.fun(3)也是跟上面一样的原理。
最后输出的结果是undefined, 0, 0, 0
第二行:b = fun(0),也就是说第二个参数为undefined,所以console.log(o) 输出undefined。
执行.fun(1)的时候,也就是说嵌套函数的参数m = 1,那此时再内存里边n是等于0的,m等于1的话,相当于返回外层函数为:fun(1, 0),那么此时console.log(o)输出的就是0。同时n在内存中的值已经变成了1。
执行.fun(2)的时候,嵌套函数的m = 2,内存中的n = 1,返回的函数为:fun(2, 1),然后console.log(o)输出1。同时内存中的n被修改为2。
执行.fun(3)的时候,嵌套函数的m = 3, 内存中的n = 2,返回的函数为:fun(3, 2),然后console.log(o)输出2。内存的n也是变成了3。
所以第二行输出的结果是undefined,0,1,2
第三行:c = fun(0),跟前面一样 结果输出undefined;
执行.fun(1),跟第二行的一样,输出0。此时n在内存中的值已经变成了1
执行c.fun(2);这里需要另外分析一下,执行到这里的时候,c其实就是被返回的一个对象,对象里边有fun的属性。所以此时执行c.fun(2)的话,其实就是在执行内部嵌套的fun函数,且m的值等于2,所以此时在内存中,n = 1,m = 2(fun(2, 1)),执行console.log(o)输出1。
执行c.fun(3),结果跟执行c.fun(2)一样,只是m的值改变了,变成fun(3, 1),执行fun(3, 1)的时候,console.log(o)还是输出1。
第三行的输出结果是:undefined,0, 1,1
总结:
闭包的产生总会有一个现象,就是一个函数嵌套着另外一个函数,并且外层函数会将嵌套的函数return出去。
在JavaScript高级程序设计里面,闭包是指有权访问另一个函数作用域中的变量的函数。
理解闭包首先要理解嵌套函数的词法作用域规则、理解作用域链。
以上如有说的不对的地方,可能是本人的理解不够深入不够正确,欢迎指正。