简单理解Javascript闭包
理解闭包,先了解一下javascript变量的作用域。有两种,全局变量和局部变量。
例子1:
<script> var a = 0; function fun(){ var b = 0; console(a+" "+b); } </script>
a是全局变量,b是局部变量。函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。
如何从外部读取函数内部的局部变量?
例子2:
function fun(num){ var b = 0; b += num; return b; } var re_b = fun(1); console.log(re_b); //1 re_b = fun(2); console.log(re_b); //2
fun()将局部变量b作为返回结果;
例子3:
function fun(){ var b = 0; function fun2(num){ b += num; return b; } return fun2 } var re_b = fun(); console.log(re_b(1)); //1 console.log(re_b(2)); //3
简单分析一下例子3代码:
定义普通函数fun;
在fun中定义变量b,普通函数fun2(参数),返回fun2;
在fun2中将参数num与b相加后赋予b,返回b;
执行fun,并把返回结果赋予re_b,此时re_b的类型为function;
执行re_b(1),结果输出1(0+1);
执行re_b(2),结果输出3(1+2);
上述方法即为闭包。
在了解闭包的作用之前,我们先了解一下 javascript 中的 垃圾回收 机制,在 javascript 中,如果一个对象不再被引用,那么这个对象就会被 gc 回收,否则这个对象一直会保存在内存中。
例子2中,执行完fun,变量b就会被释放回收;
例子3中,fun2定义在fun中,即fun2依赖于fun,全局变量re_b引用fun2,fun就间接被引用,即fun和fun2与re_b共存亡。只要re_b没被释放回收,变量b就一直在内存中。这也就是闭包的作用,fun执行完并返回后,闭包使得javascript的垃圾回收机制gc不会收回fun所占用的资源。
一句话说,当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。
闭包的应用场景:保护函数内的变量安全;在内存中维持一个变量;通过保护变量的安全实现js私有属性和私有方法。
闭包的一个简单应用:
for(var i=0;i<5;i++){ settimeout(function(){ console.log(i) },1000*i) }
结果为,每秒钟输出一个5,一共输出5次。
for(var i=0;i<5;i++){ (function fun(i) { settimeout(function(){ console.log(i) },1000*i) })(i) }
结果为,每秒钟输出一个数,0,1,2,3,4。
第一个例子中每次循环中的settimeout回调函数记住的i的值是for循环作用域中的值,此时都是5,而第二个例子记住的i的数为settimeout的父级作用域自执行函数中的i的值,依次为0,1,2,3,4。
注意点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,滥用闭包,会造成网页的性能问题,在ie中可能导致内存泄露