zoukankan      html  css  js  c++  java
  • 闭包的原理,优缺点,应用场景,常见面试题总结

    闭包的原理,优缺点,应用场景,常见面试题总结

    1.概念

    闭包:可以把闭包理解成一个函数,一个父函数里面嵌套的子函数(也就是函数中的函数),且该子函数必须使用了父函数的变量。

    如:

     function f1(){
           var b=2;
           function f2(){
               b++;
               console.log(b);
           }
           return f2;
        };
        var f=f1();
        f();
    

    在上面代码中,f1()是父函数,而f2()是f1()的子函数,且f2中使用了父函数中的变量b。在这里,f2就是闭包。

    闭包形成条件:

    1. 必须有一个内嵌函数

    2. 内嵌函数必须引用外部函数中的变量

    3. 外部函数的返回值必须是内嵌函数

    2.生命周期

    产生:在嵌套的子函数定义执行完成时就产生了

    死亡:在嵌套的内部函数成为垃圾对象时

     function f1(){
            //此时就已经产生闭包(因为函数提升)
           var b=2;
           function fn(){
               b++;
               console.log(b);
           }
           return fn;
        };
        var f=f1();
        f();
        f=null//闭包消失,因为内部函数成为了垃圾对象(没有变量在引用它)
    

    3.优缺点

    优点:

    (1)可以让子函数内的变量被访问

    (2)可以让子函数的变量的值保留在内存里面不被清除

    (3)方便调用上下文的局部变量

    (4)加强封装性

    缺点:

    (1)由于闭包会让子函数的变量的值保留在内存里面,就容易造成大量内存被占用,内存消耗过大,可能会导致内存泄漏,影响网页性能。解决方法:及时清除不使用的局部变量,也就是赋值null。

    (2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    4.常见面试题

    (1)

    function fun(n,o) {
        console.log(o);
            return {
                fun:function(m) {
                    return fun(m,n);
                }
            };
    }
    var a = fun(0); a.fun(1);  a.fun(2);  a.fun(3);  //undefined,0,0,0
    var b = fun(0).fun(1).fun(2).fun(3);             //undefined,0,1,2
    var c = fun(0).fun(1);  c.fun(2);  c.fun(3);     //undefined,0,1,1
    

     第一行:fun(0)即fun(0,o),o并未赋值->undefined,  a其实是function()函数,也就是a是一个闭包,a=fun(0)返回的是fun(m,0),所以后面的fun(0); a.fun(1); a.fun(2); a.fun(3)都为0,因为闭包中的n没有变,都是同一个闭包a。

    第二行:

    同样,fun(0)即fun(0,o),o并未赋值->undefined,    fun(0).fun(1)->fun(1,0)这时输出0,fun(0).fun(1).fun(2)->fun(0,1).fun(2)->fun(2,1)这时输出1,

    fun(0).fun(1).fun(2).fun(3)->fun(2,1).fun(3)->fun(3,2),这时输出2

    第三行:由于后面两个c.fun(2); c.fun(3)都是同一个闭包c在起作用,所以后面都是1

    (2)

    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(),所以调用result(),就是执行f2,由于全局变量n为999,所以这里就是999。

    nAdd()这里执行了一遍函数,n变成了1000。

    再执行一遍result(),此时n已经是1000了

    (3)

       function f1() {
            var n = 999;
            nAdd = function () {
              n += 1;
            };
            function f2() {
              alert(n);
            }
            return f2;
          }
          var result1 = f1();
          var result2 = f1();
          result1(); // 999
          result2(); //999
          nAdd();
          result1(); // 是999而不是1000,这是为何呢?
          result2(); //1000
    

    var result1 = f1();

    var result2 = f1();
    这两行调用了两次f1(),相当于分别执行了以下两段代码,
    执行result1=f1()时:
     function f1(){
        var n=999;
        //n在result1中的引用为temp1
        var temp1 = n;
        nAdd=function(){
            temp1 += 1;
        };
        function f2(){
          alert(temp1);
        }
        return f2;
      }
    

     执行result2=f1()时:

    function f1(){
        var n=999;
         //n在result2中的引用为temp2
        var temp2 = n;
        nAdd=function(){
            temp2 += 1;
        };
        function f2(){
          alert(temp2);
        }
        return f2;
      }
    

     由于result1和result2分别形成了闭包,分别对n进行了保存,所以顺着顺序执行nAdd();时,这里是对result2闭包中的n进行了修改,result1闭包把它自己的n保护起来了。

    所以执行完nAdd(),result1()还是999,result2()变成1000。

    (4)

    function fn(){//创建父函数(爸爸)
       var arr = [];
       for(var i = 0;i < 5;i ++){//这里循环相当于创建了五个子函数(儿子)
    	 arr[i] = function(){
    		 return i;
    	 }
       }
       return arr;
    }
    var list = fn();//这里只调用了一次父函数,
    for(var i = 0,len = list.length;i < len ; i ++){
       console.log(list[i]());
    }  //5 5 5 5 5
    
     

    参考博客:

    https://blog.csdn.net/yingzizizizizizzz/article/details/72887161

    https://blog.csdn.net/weixin_43586120/article/details/89456183

    https://blog.csdn.net/yingzizizizizizzz/article/details/77726346

    https://blog.csdn.net/u011043843/article/details/46640847?utm_source=app&app_version=4.5.7

  • 相关阅读:
    mysql报错:java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.
    MD5登陆密码的生成
    15. 3Sum、16. 3Sum Closest和18. 4Sum
    11. Container With Most Water
    8. String to Integer (atoi)
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    几种非线性激活函数介绍
    AI初探1
    AI初探
  • 原文地址:https://www.cnblogs.com/bxtfdxg/p/14622460.html
Copyright © 2011-2022 走看看