@greenfavo
2015-12-15T13:25:20.000000Z
字数 1463
阅读 799
博客
官方定义:函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中成为“闭包”。即函数定义时的作用域链到函数执行时依然有效。通俗地理解闭包就是指有权访问另一个函数作用域中的变量的函数。创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。
在循环中输出索引常常会遇到这种bug。
var data=[];for(var k=0;k<3;k++){data[k]=function(){console.log(k);}}data[0]();//3data[1]();//3
上面的例子返回的结果总是i的最后一个值,不是我们期望的和数组下标相对应的i的值。这是因为同一个上下文中创建的闭包是共用一个[[Scope]]属性的。因此上层上下文中的变量“k”是可以很容易就被改变的。这样一来,在函数激活的时候,最终使用到的k就已经变成了3了。如下所示,创建一个闭包就可以解决这个问题了:
//正确写法1var data=[];for(var k=0;k<3;k++){(function(i){//i是形参data[i]=function(){console.log(i);}})(k)//k是实参}data[0]();//0data[1]();//1//正确写法2var data=[];for(var k=0;k<3;k++){data[k]=(function(i){return function(){console.log(i);}}(k));// 传入"k"值}data[0]();//0data[1]();//1//正确写法3//这种写法data[k]就立即执行了var data=[];for(var k=0;k<3;k++){data[k]=function(i){console.log(i);}(k)}
将循环索引作为参数传入函数表达式中就可以保存这个局部变量,到调用函数时还可以使用。
function aaa() {var a = 1;return function(){console.log(a++)};}var fun = aaa();fun();// 1 执行后 a++,,然后a还在~fun();// 2aaa = null;//a被回收!!
闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗。所以使用完后将它设为null就会回收了。
函数定义时的作用域链到函数执行时依然有效。
function a(){var x=1;return function(){x+=1;console.log(x);}}var b=a();b();//2b();//3
function func(x,y){x=x||1;y=y||2;var aaa=function(){console.log(x+y);};var sss=function(){console.log(x-y);};return{add:aaa,sub:sss};}var a=func();a.add();//3a.sub();//-1a.aaa();//报错
1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。主要应用闭包场合主要是为了:设计私有的方法和变量。一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域。但闭包的情况不同!