[关闭]
@greenfavo 2015-12-15T21:25:20.000000Z 字数 1463 阅读 694

浅谈 js 闭包

博客


官方定义:函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中成为“闭包”。即函数定义时的作用域链到函数执行时依然有效。通俗地理解闭包就是指有权访问另一个函数作用域中的变量的函数。创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。

闭包经典案例

在循环中输出索引常常会遇到这种bug。

  1. var data=[];
  2. for(var k=0;k<3;k++){
  3. data[k]=function(){
  4. console.log(k);
  5. }
  6. }
  7. data[0]();//3
  8. data[1]();//3

上面的例子返回的结果总是i的最后一个值,不是我们期望的和数组下标相对应的i的值。这是因为同一个上下文中创建的闭包是共用一个[[Scope]]属性的。因此上层上下文中的变量“k”是可以很容易就被改变的。这样一来,在函数激活的时候,最终使用到的k就已经变成了3了。如下所示,创建一个闭包就可以解决这个问题了:

  1. //正确写法1
  2. var data=[];
  3. for(var k=0;k<3;k++){
  4. (function(i){//i是形参
  5. data[i]=function(){
  6. console.log(i);
  7. }
  8. })(k)//k是实参
  9. }
  10. data[0]();//0
  11. data[1]();//1
  12. //正确写法2
  13. var data=[];
  14. for(var k=0;k<3;k++){
  15. data[k]=(function(i){
  16. return function(){
  17. console.log(i);
  18. }
  19. }(k));// 传入"k"值
  20. }
  21. data[0]();//0
  22. data[1]();//1
  23. //正确写法3
  24. //这种写法data[k]就立即执行了
  25. var data=[];
  26. for(var k=0;k<3;k++){
  27. data[k]=function(i){
  28. console.log(i);
  29. }(k)
  30. }

将循环索引作为参数传入函数表达式中就可以保存这个局部变量,到调用函数时还可以使用。

内部函数闭包,避免污染全局变量

  1. function aaa() {
  2. var a = 1;
  3. return function(){
  4. console.log(a++)
  5. };
  6. }
  7. var fun = aaa();
  8. fun();// 1 执行后 a++,,然后a还在~
  9. fun();// 2
  10. aaa = null;//a被回收!!

闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗。所以使用完后将它设为null就会回收了。

局部变量累加

函数定义时的作用域链到函数执行时依然有效。

  1. function a(){
  2. var x=1;
  3. return function(){
  4. x+=1;
  5. console.log(x);
  6. }
  7. }
  8. var b=a();
  9. b();//2
  10. b();//3

私有成员

  1. function func(x,y){
  2. x=x||1;
  3. y=y||2;
  4. var aaa=function(){
  5. console.log(x+y);
  6. };
  7. var sss=function(){
  8. console.log(x-y);
  9. };
  10. return{
  11. add:aaa,
  12. sub:sss
  13. };
  14. }
  15. var a=func();
  16. a.add();//3
  17. a.sub();//-1
  18. a.aaa();//报错

使用闭包的好处

1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在

总结

闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。主要应用闭包场合主要是为了:设计私有的方法和变量。一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域。但闭包的情况不同!

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注