对于新手来说,闭包的概念往往有些晦涩。书上的概念描写的非常简短,网上的各类文章又常常是长篇大论地探讨闭包的作用呀,影响呀,看到最后,觉得是越看越晕,越来越搞不懂什么是闭包了,所以在这里分享自己对闭包的浅显的理解,希望对新手有所帮助,相互交流。
>>进入主题
什么是闭包:闭包是指有权访问另一个函数作用域的变量的函数。--《javascript高级程序设计》
书上的概念就这么一句话,其实闭包就是像这句话定义的一样简单。如果有一个函数fun2,它可以访问在其它函数如fun1中的局部变量,那么它(fun2)就是闭包。创建闭包的简单方式,就在在函数内部创建另一个函数,下面例子创建了个简单的闭包
1 function fun1 () { 2 var a = 0; 3 function fun2 () { 4 console.log(a); // 在这个函数fun2中可以访问另一个函数中的变量a,所以fun2()就是一个闭包。 5 } 6 fun2(); 7 }
上面这个闭包运行其实和大家所熟悉的函数运行没什么两样,也不会出现各种关于闭包的问题,正常地访问外部函数的变量,数据。以上就是闭包的定义,非常简单,我们不用把它想得过于复杂。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~定义分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
那么问题来了,为什么闭包那么重要呢,不是说好的有各种注意事项的么。是的,我们通常可以像上面那样直接在外部函数内调用函数,即直接调用闭包。但是有时候会出现其他的调用情形,在其他地方调用内部函数(闭包),使这个闭包逃离定义它们的外部函数。
所以接下来我们简单讨论闭包如何在其他地方被调用(逃离),以及会产生怎样的影响(基于闭包在其他地方被调用的情形,并不是所有闭包都会出现这种影响)
逃离方式:
1.将内部函数指定给一个全局变量;
var globalVar; function outer() { console.log(‘outer‘); function inner(){ console.log(‘inner‘); } globalVar = inner; } outer(); // outer globalVar(); // inner;
在这个例子中inner()通过全局变量的引用成功逃离,现在可以在全局中调用,而且可以引用outer()的变量
2.通过返回值来‘营救‘内部函数的引用
function outer() { console.log(‘outer‘); function inner(){ console.log(‘inner‘); } return inner; } var fn = outer(); // outer fn(); // inner;
在这个例子中inner()通过返回值成功逃离,现在可以在全局中调用,而且可以引用outer()的变量
上面两个例子中对内存的影响:
本来正常的情况下是函数调用结束之后函数的执行环境离开环境栈,定义的变量废弃(废弃与垃圾收集机制有关),活动变量(变量对象)会被销毁,内存释放。但是现在因为闭包的作用域链包含了外部函数的变量对象,外部函数的变量有可能再被引用,垃圾收集机制不会将外部函数的变量废弃,在内存保留的外部函数的变量对象。这样就加大了对内存的占用。