其实关于闭包的定义,不少种说法,而关于闭包的解释,更是多不胜数了。不少说得很是复杂,也有不少人有着不一样的理解,在这里我就从最容易理解的角度去解释闭包的概念,若有不正确的地方,请指出。javascript
闭包,其实就是可以读取函数内部变量的函数。java
举个例子:git
//全局环境 function outer(){ var big = 20; } console.log(big);
固然了,执行上面这样的代码会报错,由于你没有在全局环境中声明big,你想访问outer函数内部的big也是不行的,由于你没有调用outer函数,压根不会建立outer的执行上下文,更不用说outer里面的big的做用域只是在outer函数内部了。github
那如何可以在外部访问到outer函数里面的big变量呢?有办法,就是闭包:面试
//全局环境 function outer(){ var big = 20; function inner(){ console.log(big); }; return inner(); } outer();//20
你执行outer函数的时候,里面返回的是调用inner函数的结果,而inner函数就是访问big变量的,因此这样就能使外部能够访问到函数里面的变量。这就是所谓的闭包,没有传说中的那么复杂,不过网上的所谓闭包面试题就解释得很复杂了。闭包
可是闭包有一个问题,就是会使得你内部访问的变量常驻内存当中,垃圾机制又没有将其回收,若是此函数再也不使用了,又没有对其进行清除,就会形成内存泄漏,若是过多使用闭包,后果可想而知。函数
其实换一个角度,咱们看这样的例子:code
//全局环境 var bigger = 30; function outer(){ console.log(bigger); } outer();//30
像上面的例子,全局环境下声明的outer函数,里面调用了全局环境的bigger变量,不又是一个闭包吗?其实没错,这是广义的闭包,不是常说的闭包,可是转头想一想,其实这个bigger是一直存在于全局的执行上下文中的全局变量,你不清除掉不也同样一直存在内存中吗?对象
一句话理解闭包类题目:若是a函数内的其余b函数用到了a函数执行上下文中的变量n,那么这个变量n的值就会一直保存在这个函数的变量对象当中,直到下一次改变它。ip
举个网上的面试例子来讲明我这个理解:
//全局环境 function fun(n,k) { console.log(k) 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);
这个例子也是随便一搜的,其余例子其实也类同,因此在这里就用我我的理解的角度去分析一下这个题。
先说var a 这一行的输出吧:
var a = fun(0)很容易知道输出undefined了,可是返回的是一个对象,这个对象的fun属性是一个匿名函数,而这个匿名函数里面又返回了一个fun函数,这个fun函数用到了变量n。好了,用上我前面的理解,能够知道fun函数里面就保存了n=0这个值,直到下一次改变它。相似以下:
var a = { fun:function(m){ return fun(m,0); } };
而从a.fun(1)、a.fun(2)、 a.fun(3)开始,你们确定知道会执行这三个函数:
f(1,0);f(2,0);f(3,0);
因此会输出undefined 0 0 0。
可能你们会懵了,你在执行f(1,0)的时候,不是n的值改成1,不是会改变了n的值了吗?后面的n的值不是变了吗?在这里我就要说说关于个人理解中,怎样为改变这个变量的值。
先再回顾一下我前面的理解:若是a函数内的其余b函数用到了a函数执行上下文中的变量n,那么这个变量n的值就会一直保存在这个函数的变量对象当中,直到下一次改变它。
改变这个变量的n值,必须经过闭包,也就是这个:
{ fun:function(m){ return fun(m,n); } };
经过这个fun属性对应的匿名函数的执行,才会在匿名函数的返回结果中改变这个n的值。
在上面的执行a.fun(1)中,只是又返回了一个新的对象,可是并无执行新对象里面的fun属性对应的匿名函数喔,那就是没有改变n的值啊,因此你继续a.fun(2)、a.fun(3)也会输出一样的结果啊。
也就是,必须有执行这样:a.fun(1).fun(1)这样,才会改变到n的值。
对于上面例题var b这一行来讲,就很容易明白var b = fun(0).fun(1).fun(2).fun(3);后面的fun(1).fun(2).fun(3)这三个中的fun其实都是属性名fun,并非声明的函数fun,因此他们都在改变n的值啊,因此也很容易明白这一行的输出结果就是undefined 0 1 2。
var c的那一行也很容易明白输出结果是undefined 0 1 1了。
关于这个题的详细理解,你们再细想一下,就很清楚了。