什么是闭包(Closure)简单来说,闭包就是一个函数,它可以访问另一个函数作用域内的变量。MDN是这样说的:闭包是一种特殊的对象。它由两部分组成:函数和创建函数的环境。环境由创建闭包时范围内的任何局部变量组成。不过在网上找了很多资料,他们对闭包的定义都不一样,所以我也不知道怎么定义闭包,就干脆不定义了,理解一下。道可以道,非常道;名字可以命名,非常有名。生成闭包创建闭包的最常见方法是在另一个函数中创建一个函数。下面例子中的闭包是一个闭包:functionfunc(){vara=1,b=2;functionclosure(){returna+b;}returnclosure;}闭包的作用域链包含了自己的作用域,并且包含了它的函数作用域和全球范围。关于闭包的注意事项通常,函数的范围及其所有变量在函数完成执行后被销毁。但是,在创建闭包之后,此函数的作用域将一直保留到闭包不再存在为止。functionmakeAdder(x){returnfunction(y){returnx+y;};}varadd5=makeAdder(5);varadd10=makeAdder(10);console.log(add5(2));//7console.log(add10(2));//12//释放对闭包的引用add5=null;add10=null;add5和add10都是闭包。它们共享相同的功能定义,但保存不同的环境。在add5的上下文中,x是5。在add10中,x是10。***通过null释放了add5和add10对闭包的引用。在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;被回收。闭包只能获取封闭函数中任何变量的最后一个值,因为闭包存储的是整个变量对象,而不是某个特定变量。functiontest(){vararr=[];for(vari=0;i<10;i++){arr[i]=function(){returni;};}for(vara=0;a<10;a++){console.log(arr[a]());}}test();//连续打印10个10s对于上面的情况,如果我们把代码改成这样:functiontest(){vararr=[];for(leti=0;i<10;i++){//Arr[i]=function(){returni;};}for(vara=0;a<10;a++){console.log(arr[a]());}}test();//Print0to9上面两段代码的解释请看我在segmentfault上的问题:thisobjectinthelinkclosurevarname="TheWindow";varobj={name:"MyObject",getName:function(){returnfunction(){returnthis.name;};}};console.log(obj.getName()());//Windowobj.getName()()其实是在全局调用了一个匿名函数范围,这指向窗口。这里我们需要明白,函数名和函数功能(或函数值)是分开的。不要以为函数在哪里,它内部的this就指向哪里。匿名函数的执行环境是全局的,所以它的this对象通常指向window。varname="TheWindow";varobj={name:"MyObject",getName:function(){varthat=this;returnfunction(){returnthat.name;};}};console.log(obj.getName()());//MyObject闭包的应用应用闭包的主要场合是设计私有方法和变量。函数内部定义的任何变量都可以被认为是私有的,因为它不能在函数外部访问。私有变量包括函数参数、局部变量和函数内定义的其他函数。可以访问私有变量的公共方法称为特权方法。functionAnimal(){//私有变量varseries="mammal";functionrun(){console.log("Run!!!");}//特权方法this.getSeries=function(){returnseries;};}module模块模式:为单例创建私有变量和方法。单例:只有一个实例的对象。JavaScript通常以对象字面量的形式创建单例对象。varsingleton={name:"percy",speak:function(){console.log("speaking!!!");},getName:function(){returnthis.name;}};上面是普通模式创建的单例,下面使用模块模式创建单例:varsingleton=(function(){//privatevariablevarage=22;varspeak=function(){console.log("speaking!!!");};//特权(或公共)属性和方法return{name:"percy",getAge:function(){returnage;}};})();匿名函数***的目的是创建闭包,也可以构建命名空间来减少全局变量的使用。从而使用闭包将代码模块化,减少全局变量的污染。varobjEvent=objEvent||{};(function(){varaddEvent=function(){//somecode};functionremoveEvent(){//somecode}objEvent.addEvent=addEvent;objEvent.removeEvent=removeEvent;})();in这段代码中的函数addEvent和removeEvent是局部变量,但是我们可以通过全局变量objEvent来使用,这样就大大减少了全局变量的使用,增强了网页的安全性。闭包计数器varcountNumber=(function(){varnum=0;returnfunction(){return++num;};})();闭包的缺陷闭包的缺点是常驻内存会增加内存占用。而且使用不当很容易造成内存泄漏。如果某些特殊任务不需要闭包,那么在不需要的其他函数中创建函数是不明智的,因为闭包会对脚本性能产生负面影响,包括处理速度和内存消耗。***以下是一些关于关闭包裹的面试问题。在下面的代码中,标记的输出是什么?functionfun(n,o){console.log(o);return{fun:function(m){returnfun(m,n);}};}vara=fun(0);//?a.fun(1);//?a.fun(2);//?a.fun(3);//?varb=fun(0).fun(1).fun(2).fun(3);//?varc=fun(0).fun(1);//?c.fun(2);//?c.fun(3);//?undefined000undefined,0,1,2undefined,011参考资料【书】《JavaScript 高级程序设计(第三版)》【文章】学习Javascript闭包(Closure)【文章】【JavaScript】【函数】闭包closure!
