浅谈闭包

124 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

闭包的定义?什么是闭包?

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

学习闭包

在学习闭包之前,我们有必要知道闭包的作用。它的具体用处可以总结为两个:

  1. 在函数外部访问函数内部的局部变量

  2. 变量持久化(使变量始终保持在内存中)

一.作用域

在了解闭包概念的时候,我们就能明白,要学习闭包,首先得明白javascript的作用域。

作用域无非两种:局部作用域和全局作用域,所对应作用域内部的变量也被称之为全局变量和局部变量。

而在javascript中,函数内部(局部作用域内)可以访问全局变量,但是在全局作用域中无法访问局部变量。

下面我们在代码内演示:

函数内部访问函数外部的全局变量

    var a = 1;
    
    function f(){
    console.log(a);
   }
    
    f(); //1
  

函数外部访问函数内部的局部变量

    function(){
        var a = 1;
    }
    
    console.log(a); //error: Function statements require a function name

二.闭包实现

既然函数外部无法获取函数内部的局部变量,那我们该如何去做才能实现闭包呢?

其实,只需要在函数内部再定义一个函数就可以了

    function f1(){
        var a = 1;
        
        function f2(){
            console.log(a);
        }
        
        return f2;
    }

如上代码所示,我们在函数f1内部又定义了一个函数f2,对于f2来说,f1内部所有变量都是可见的。这是因为js内部的链式作用域:子对象内部使用了不存在的变量,它会一级一级的向上寻找父对象内部变量。

f2内部没有变量a,但是f1有啊,所以f2拿得到a变量,之后再将f2作为返回值,那么我们就可以在f1函数外部拿到f1内部变量a了。

对上面代码进行最后处理如下


function f1(){
        var a = 1;
        
        function f2(){
            console.log(a);
        }
        
        return f2;
    }
    
    var result = f1();
    
    result(); //1

在上面这段代码中,result实际上就是闭包f2函数。

上面这个例子我们实现了闭包函数,也明白了闭包的用途(1)在函数外部访问函数内部的局部变量,接下来我们在用一个例子说明闭包的用途(2)变量持久化

首先我们先看一段代码

 function f1(){

    var a = 1;

    add=function(){
        a += 1;
       }

       console.log(a);

  }

  f1();//1
  
   add();
   
   f1();//1
 

上面一段代码 执行两次f1()函数,结果都为1.就是因为f1()函数运行结束后就被js的垃圾回收机制从内存中清除了,内部的a变量也就随之消失,因此函数add并没有意义。

下面我们用闭包的方式写一下上面的代码

 function f1(){

    var a = 1;

    add=function(){
        a += 1;
       }
       
      function f2(){
       console.log(a);
      }
      
       return f2;
  }
    
    var result = f1();
    
  result();//1
  
   add();
   
   result();//2
   

我们发现运行结果变了,那为什么会这样呢?

原因就是:f2函数被赋予了一个全局变量,导致它会一直存在于内存;而f2属于f1函数的内部函数,它依附于函数f1,因此,函数f1也会一直存在于内存,不会在被调用后立马清除。这也是闭包的作用(2).

三.闭包注意事项

从上面我们了解了闭包,并知道闭包怎么使用。而在使用闭包的时候,我们也要注意闭包可能引起的问题。

1.闭包可以在函数外部改变函数内部的变量,而这个改变从根本上说,其实就是子函数在改变父函数的值;所以,如果你把父函数当作对象使用,把闭包当作它的公用方法,把内部变量当作它的私有属性,这时一定要小心,不要随便改变父函数内部变量的值。

2.由于闭包可以持久化变量,即让函数内部变量一直在内存中,会增加内存消耗,因此不能滥用闭包,否则会造成网页的性能问题,甚至内存泄漏!解决方法,在退出函数前,将不使用的全局变量全部删除。

好啦,上面就是个人对闭包的理解。

文章是偶然看了阮一峰大网络日志,之后做的总结,算是个人理解的一些总结。