我们先来看一个简单的例子:
1 function one(){ 2 var a=30; 3 return function(){ 4 return a;
6 } 7 } 8 var func=one(); 9 func();
显然,最后的结果为:30;
在上面的例子中,我们执行了 func=one();之后,返回的是return的匿名函数,该匿名函数任然能够访问外部的局部变量 a,这种情况就是我们所说的闭包。在一般的函数中,函数在执行完成之后,就会释放掉该函数中的局部变量,但是闭包不会,闭包会使该局部变量一直保存在内存中。
在一些专业的文献中对闭包的解释是:闭包是指函数或函数的引用,与一个引用环境绑定在一起,这个引用环境是一个存储该函数每个非局部变量的表。
从简单来讲,闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
闭包的作用:一是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
但是,我们有时会遇到这样的情况:比如说,我们想要这个函数返回所有的 i 的值:
1 function one(){ 2 var a = new Array(); 3 for(var i=0;i<5;i++){ 4 a[i] = function(){ 5 return i; 6 }; 7 } 8 return a; 9 }
表面上看,每个函数都应该返回自己的索引值,但实际上,每个函数都返回5.因为每个函数的作用域链中都保存着 one() 函数的活动对象,他们都引用的是当 one() 函数返回后的 i 的值,即为 5 。这时,我们如果想要达到预期的效果,我们可以通过穿件另一个匿名函数强制让闭包行为符合预期:
1 function one(){ 2 var a = new Array(); 3 for(var i=0;i<5;i++){ 4 a[i] = function(num){ 5 return function(){ 6 return num; 7 }; 8 }(i); 9 } 10 return a; 11 }
在修改过后的代码中,我们重新定义了一个匿名函数,而且是立即执行的匿名函数,给这个函数传入了一个参数,即每次循环的 i 的值,这时最内层返回的 num 就是每次 i 的循环的值,可以达到我们的预期。
总结:从上面所说到的闭包的作用“可以使变量始终保持在内存中“中可以得到,有时在比较复杂的作用域环境中,在函数被调用之后,任然无法知道后面在何时还会再用到这些环境,所以会导致空间浪费,内存泄漏,性能消耗等坏处。所以我们要合理的使用闭包。