JavaScript里的闭包

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36065997/article/details/79090321

JavaScript中的闭包,无非就是变量解析的过程。

闭包的相关定义

1.什么是闭包

闭包是值能够读取其他函数内部变量的函数。也就是连接函数内部和函数外部的桥梁。

2.闭包有什么用处

     ①.读取函数变量
     ②.让这些变量的值始终存在内存中。由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,因此要慎重使用。

3.闭包的创建

因此创建闭包的常见方式就是在一个函数内部创建另一个函数。

     function f1(){
    var n=999;
    function f2(){
      alert(n); 
    }
    return f2;
  }
  var result=f1();
  result(); // 999

f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量,其中f2就是闭包,闭包就是能够读取其他函数内部变量的函数

function f1(){
    var n=999;
    nAdd=function(){n+=1};
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

闭包与变量

闭包只能取得包含函数中任意变量的最后一个值,因为闭包所保存的是整个变量的对象,而不是某个特殊的变量。

例子

function box(){
 var result = new Array();

 for(var i=0;i<10;i++){
   result[i] = function(){  //匿名函数里面没有i这个变量,所以会从父级的函数中去找,当找到i时,由于闭包的原因,外层循环完毕之后才返回i,因此匿名函数内部输出的都是10
     return i;
   };
 }

 return result;  
}

console.log(box()[0]());    //结果:10

可以通过创建另一个匿名函数强制让闭包的行为符合预期:

function box(){
 var result = new Array();

 for(var i=0;i<10;i++){
   result[i] = (function(num){
     return function(){
       return num;
     };
   })(i);
 }

 return result;  
}

console.log(box()[0]());  //结果:0

上述代码,没有直接将闭包赋给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组。
在调用每个匿名函数时,我们传入了变量i,由于函数参数是按值传递的,所以会将变量i的当前值复制给参数num。
而在这个匿名函数内部,又创建并返回一个访问num的闭包。
这样一来,result数组中的每个函数都有自己num变量的一个副本,因此可以返回各自不同的数值。

ES6中,用let声明块级变量,所以上述代码可以更新为

function box(){
 var result = new Array();

 for(let i=0;i<10;i++){
   result[i] = function(){  
     return i;
   };
 }

 return result;  
}

console.log(box()[0]());    //结果:0

猜你喜欢

转载自blog.csdn.net/baidu_36065997/article/details/79090321