精华内容
下载资源
问答
  • 闭包

    2017-09-24 14:29:03
    闭包

    闭包的形成与变量的作用域以及变量的生存周期密切相关
    1、变量 的作用域
    变量的作用域就是指变量的有效范围。我们最常谈到的是在函数中声明的变量作用域。
    当在函数中声明一个变量的时候,如果该变量前面没有带上关键字var,这个变量就会成为全局变量,这当然是一种容易造成命名冲突的做法。
    另外一种情况是用var关键字在函数中声明变量,这时候的变量即是局部变量,只有在该函数内部才能访问到这个变量,在函数外面是访问不到的。
    在JavaScript中,函数可以用来创造函数作用域。此时的函数像是一层半透明的玻璃,在函数里面可以看到外面的变量,而在函数外面则无法看到函数里面的变量。这是因为当在函数中搜索一个变量的时候,如果该函数内并没有 声明这个变量,那么此次搜索的过程会随着代码执行环境创建的作用域链往外层逐层搜索,一直搜索到全局对象为止。变量的搜索是从内到外而非从外到内的。

    var a = 1;
    var fun1 = function() {
        var b = 2;
        var fun2 = function() {
            var c = 3;
            alert( b );// 2
            alert( a ); // 1
        };
        fun2();
        alert( c ); // Uncaught ReferenceError: c is not defined
    };
    fun1();
    

    2、变量的生存周期
    对于全局变量来说,全局变量的生命周期当然是永久的,除非我们主动销毁这个全局变量。而对于在函数内用var关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数调用的结束而被销毁。

    var func = function() {
        var a = 1; // 退出函数后局部变量a将被销毁
        alert( a );
    };
    func();
    

    现在我们来看看下面这段代码:

    var func = function() {
        var a = 1;
        return function() {
            a++;
            alert( a );
        };
    };
    var f = func();
    f(); // 2
    f(); // 3
    f(); // 4
    f(); // 5
    

    跟我们之前的推论相反,当退出函数后,局部变量a并没有消失,而是似乎一直在某个地方存活着。这是因为当执行var f = func( );时,f返回了一个匿名函数的引用,它可以访问到func( )被调用时产生的环境,而局部变量a一直处在这个环境里。既然局部变量所在的环境还能被外界访问,这个局部变量就有了不被销毁的理由。在这里产生了一个闭包结构,局部变量的生命看起来被延续了。
    利用闭包我们可以完成许多奇妙的工作,下面介绍一个闭包的经典应用。假设页面上有5个div节点,我们通过循环来给每个div绑定onclick事件,按照索引顺序,点击第一个div时弹出0,点击第二个div时弹出1,一次类推,代码如下:

    <body>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
    
        <script>
            var nodes = document.getElementByTagName( 'div');
            for( var i = 0,len = nodes.length; i< len; i++) {
                nodes[i].onclick = function() {
                    alert( i );
                };
            };
        </script>
    </body>
    

    测试这段代码就会发现,无论点击哪个div,最后弹出的结果都是5。这是因为div节点的onclick事件是被异步触发的,当事件被触发时,for循环早已结束,此时变量i的值已经是5,所以在div的onclick事件函数中顺着作用域链从内到外查找变量i时,查找到的值总是5。
    解决方法是在闭包的帮助下,把每次循环的i值都封闭起来。当在事件函数中顺着作用域链中从内到外查找变量i时,会先找到被封闭在闭包环境中的i,如果有5个div,这里的i就分别是0,1,2,3,4:

    for( var i = 0, len = nodes.length; i < len; i++ ) {
        (function(i) {
            nodes[i].onclick = function() {
                console.log(i);
            };
        })(i);
    };
    

    根据同样的道理,我们还可以编写如下一段代码:

    var Type = { };
    for ( var i = 0, type; type = [ 'String', 'Array', 'Number' ][ i++ ];) {
        (function(type) { 
            Type[ 'is' + type ] = function( obj ) {
                return Object.prototype.toString.call(obj) === '[Object' + type + ']';
            };
        }(type);
    };
    Type.isArray( [] ); //true
    Type.isString( 'str' ); //true
    

    3、闭包的更多作用

    • 封装变量

    闭包可以帮助把一些不需要暴露在全局的变量封装成“私有变量”。假设有一个计算乘积的简单函数:

    var mult = function() {
        var a = 1;
        for( var i = 0,l = arguments.length; i < l ;i++)
            a = a*arguments[i];
        };
        return a;
    };
    

    mult函数接受一些number类型的参数,并返回这些参数的乘积。现在我们觉得对于那些相同的参数来说,每次都进行计算是一种浪费,我们可以加入缓存机制来提高这个函数的性能:

    var cache = { };
    var mult = function() {
        var args = Array.prototype.join.call( arguments, ',');
        if( cache[ args ] ) {
            return cache[ args ];
        };
        var a = 1;
        for( var i = 0,l = arguments.length; i < l;i++) {
            a = a*arguments[i];
        };
        return cache[ args ] = a;
    };
    alert( mult(1,2,3) ); // 6
    alert( mult(1,2,3) ); // 6
    

    我们看到cache这个变量仅仅在mult函数中被使用,与其让cache变量跟mult函数一起平行的暴露在全局作用域下,不如把它封闭在mult函数内部,这样可以减少页面中的全局变量,以避免这个变量在其他地方被不小心修改而引发错误。代码如下:

    var mult = (function() {
        var cache = {};
        return function() {
            var args = Array.prototype.join.call( arguments, ',');
            if(args in cache) {
                return cache[ args ];
            };
            var a = 1;
            for( var i = 0,l = arguments.length; i<l;i++) {
                a = a*arguments[i];
            };
            return cache[args] = a;
        }
    })();
    

    提炼函数是代码重构中的一种常见技巧。如果在一个大函数中有一些代码块能够独立出来,我们常常把这些代码块封装在独立的小函数里面。独立出来的小函数有助于代码复用,如果这些小函数有一个良好的命名,它们本身也起到了注释的作用。如果这些小函数不需要在程序的其他地方使用,最好是把它们用闭包封闭起来。代码如下:

    var mult = (function() {
        var cache = {};
        var calculate = function() {// 封闭calculate函数
            var a = 1;
            for( var i = 0,l = arguments.length;i<l;i++) {
                a = a*arguments[i];
            };
            return a;
        };
        return function() {
            var args = Array.prototype.join.call( arguments, ',');
            if( args in cache ) {
                return cache[args];
            };
            return cache[ agrs ] = calculate.apply(null,arguments);
        }
    })();
    
    • 延续局部变量的寿命

    img对象经常用于进行数据上报,如下所示:

    var report = function( src ) {
        var img = new Image();
        img.src = src;
    };
    report( 'http://xxx.com/getUserInfo');
    

    但是通过查询后台的记录我们得知,因为一些低版本浏览器的实现存在bug,在这些浏览器下使用report函数进行数据上报会丢失30%左右的数据,也就是说,report函数并不是每一次都成功发起了HTTP请求。丢失数据的原因是img是report函数中的局部变量,当report函数调用结束后,img局部变量随即被销毁,而此时或许还没来得及发出HTTP请求,所以此次请求就会丢失掉。
    现在我们把img变量用闭包封闭起来,便能解决请求丢失的问题:

    var report = (function() {
        var imgs = [];
        return function( src ) {
            var img = new Image();
            imgs.push(img);
            img.src = src;
        }
    })();
    

    4、闭包和面向对象设计
    过程与数据的结合是形容面向对象的“对象”时经常使用的表达。对象以方法的形式包含了过程,而闭包则是在过程中以环境的形式包含了数据。通常用面向对象思想能实现的功能,用闭包也能实现。反之亦然。在JavaScript语言的祖先Scheme语言中,甚至都没有提供面向对象的原声设计,但可以使用闭包来实现一个完整的面向对象系统。
    下面来看看这段跟闭包相关的代码:

    var extent = function() {
        var value = 0;
        return {
            call: function() {
                value++;
                console.log(value);
            }
        };
    };
    var extent = extent();
    extent.call(); // 1
    extent.call(); // 2
    extent.call(); // 3
    

    如果换成面向对象的写法,就是:

    var extent = {
        value: 0,
        call: function() {
            this.value++;
            console.log(this.value);
        }
    };
    extent.call(); // 1
    extent.call(); // 2
    extent.call(); // 3
    

    或者:

    var Extent = function() {
        this.value = 0;
    };
    Extent.prototype.call = function() {
        this.value++;
        console.log(this.value);
    };
    var extent = new Extent();
    extent.call();
    extent.call();
    extent.call();
    

    5、用闭包实现命令模式
    在完成闭包实现的命令模式之前,我们先用面向对象的方式来编写一段命令模式的代码。虽然还没有进入设计模式的学习,但这个作为演示作用的命令模式结构非常简单,代码如下:

    <button id="execte">点击我执行命令</button>
    <button id="undo">点击我执行命令</button>
    
    <script>
        var Tv = {
            open: function() {
                console.log('打开电视机');
            },
            colse: function() {
                console.log('关上电视机');
            }
    
        };
        var OpenTvCommand = function(receiver) {
            this.receiver = receiver;
        };
        OpenTvComman.prototype.execute = function() {
            this.receiver.open(); //执行命令,打开电视机
        };
        OpenTvComman.prototype.undo = function() {
            this.receiver.close(); //撤销命令,关闭电视机
        };
        var setCommand = function(command) {
            document.getElementById( 'execute' ).onclick = function() {
                comman.execute(); //打开电视机
            };
            document.getElementById( 'undo' ).onclick = function() {
                comman.undo(); //关闭电视机
            };      
        };
        setCommand( new OpenTvCommand( Tv ));
    </script>
    

    命令模式的意图是把请求封装为对象,从而分离请求的发起者和请求的接收者(执行者)之间的耦合关系。在命令被执行之前,可以预先忘命令对象中植入命令的接收者。
    但在JavaScript中,函数作为一等对象,本身就可以四处传递,用函数对象而不是普通对象来封装请求显得更加简单和自然。如果需要往函数对象中预先植入命令的接收者,那么闭包可以完成这个工作。在面向对象版本的命令模式中,预先植入的命令接收者被当成对象的属性保存起来;而在闭包版本的命令模式中,命令接收者会被封闭在闭包形成的环境中,代码如下:

    var Tv = {
        open: function() {
            console.log('打开电视机');
        },
        colse: function() {
            console.log('关上电视机');
        }
    };
    var createCommand = function(receiver) {
        var execute = function() {
            return receiver.open(); //执行命令,打开电视机
        }
        var undo = function() {
            return receiver.close(); //执行命令,关闭电视机
        }
        return {
            execute: execute,
            undo: undo
        }
    };
    var setCommand = function(command) {
        document.getElementById( 'execute' ).onclick = function() {
            comman.execute(); //打开电视机
        };
        document.getElementById( 'undo' ).onclick = function() {
            comman.undo(); //关闭电视机
        };      
    };
    setCommand( new createCommand( Tv ));
    

    6、闭包与内存管理
    闭包是一个非常强大的特性,但人们对其也有诸多误解。一种耸人听闻的说法是闭包会造成内存泄露,所以要尽量减少闭包的使用。
    局部变量本来应该在函数退出的时候被解除引用,但如果局部变量被封闭在闭包形成的环境中,那么这个局部变量就能一直生存下去。从这个意义上看,闭包的确会使一些数据无法被及时销毁。使用闭包的一部分原因是我们选择主动把一些变量封闭在闭包中,因为可能在以后还需要使用这些变量,把这些变量放在闭包中和放在全局作用域,对内存方面的影响是一致的,这里并不能说成是内存泄露。如果在将来需要回收这些变量,我们可以手动把这些变量设置成null。
    跟闭包和内存泄露有关系的地方是,使用闭包的同时容易形成循环引用,如果闭包的作用域链中保存着一些DOM节点,这时候就有可能造成内存泄露。但这本身并非闭包的问题,也并非JavaScript的问题。在IE浏览器中,由于BOM和DOM中的对象是使用C++以COM对象的方式实现的,而COM对象的垃圾收集机制采用 是引用计数策略。在基于引用计数策略的垃圾回收机制中,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的。
    同样,如果要解决循环引用带来的内存泄露问题,我们只需要把循环引用中的变量设为null即可。将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收它们占用的内存。

    展开全文
  • java 闭包方法 什么是封包? 闭包是一个内部函数,可以访问外部(封装)函数的变量-作用域链。 闭包具有三个作用域链:它可以访问自己的范围(在大括号之间定义的变量),可以访问外部函数的变量,并且可以访问...

    java 闭包方法

    什么是封包?

    闭包是一个内部函数,可以访问外部(封装)函数的变量-作用域链。 闭包具有三个作用域链:它可以访问自己的范围(在大括号之间定义的变量),可以访问外部函数的变量,并且可以访问全局变量

    简单来说,就是函数内部的一个函数,它依赖于外部函数中的变量来工作。

    理解概念的最好方法就是做到这一点。

    因此,让我们在闭包上有一些例子。

    function doSomeMath(){
    var a=5;
    var b=4;
    var sum=a+b;
    return sum;
    }
    var theResult = doSomeMath();
    console.log("The result:", theResult);

    我们在这里进行一些数学运算,设置三个变量,然后将一个变量添加到另一个变量中,然后返回总和。 现在,让我们仔细看看浏览器将如何正确处理此代码。 当我们在浏览器中运行脚本时。 它首先发现此功能doSomeMath,但对此没有任何作用。 然后,它进入此处并找到变量theResult,并看到已将doSomeMath分配给该变量。

    这意味着它需要运行doSomeMath,因此它跳至函数,设置三个变量,执行数学运算,然后将结果放入sum变量中,然后返回sum变量。 然后将sum变量的内容放入Result中,并有效关闭doSomeMath函数,并丢弃其中的所有内容。 我们在Result中剩下的唯一值是9,这意味着如果我进入控制台,然后尝试调用A或B或求和,我什么也没得到。

    那是因为它们位于函数doSomeMath的范围之内。 我们现在不在范围内,并且这些变量不存在。 到目前为止,这里没有新内容。 现在让我们稍微修改一下这个例子。

    function doSomeMath(){
    var a=5;
    var b=4;
    function multiply(){
    var result = a*b;
    return result;
    }
    return multiply;
    }
    var theResult = doSomeMath();
    console.log("The result:", theResult);

    如果我现在保存此内容,您将在控制台的此处看到,变量theResult现在保存了total函数与其所有内容的乘积。

    如果我现在保存此内容,您将在控制台的此处看到,变量theResult现在保存了total函数与其所有内容的乘积。

    这很奇怪,根据我们对功能如何工作的了解,这是行不通的。 我为什么这么说? 好吧,请考虑一秒钟。 浏览器从右上方读取? 因此,它首先找到函数doSomeMath,但对此没有执行任何操作。 然后,它跳到变量Result,并看到已将doSomeMath分配给它,因此它上升到顶部,并运行整个函数。 它设置了两个变量,注册了乘法函数,然后向下移动到底部并看到哦,我想返回乘法函数,但是我不想运行它,我只是想像返回它一样它是一个变量,所以我将这个乘法函数放在TheResult中,然后关闭其他所有内容。

    因此从技术上讲,这意味着A和B应该不复存在,但是如果我们在控制台中查看,显然它不存在,显然它仍然存在。 这就是所谓的闭包。 发生的是,此内部函数乘法依赖于在外部函数中定义的变量。 而且浏览器足够聪明,可以理解哦,这些东西是相关的,因此,即使我们关闭了doSomeMath函数,我仍将保留这两个变量,以便乘法函数仍然可以使用它们。

    那么为什么要具有此功能?

    好吧,它有一些有趣的实际应用。 让我向您展示一个非常简单的示例。 我将清除所有代码,然后重新开始。 如果您曾经在CSS中使用过Ems,那么您会知道计算起来有些麻烦,尤其是如果您知道要查找的像素值是多少,然后必须弄清楚类似的Em价值将是。

    Ems的诀窍是,如果您知道当前上下文的像素值,则可以只获取您要查找的像素值,比如说32个像素,然后将其除以当前上下文像素值,如果仅在整个浏览器中正常工作通常为16。所需像素值32的结果除以根像素值16可得到Em值。 使用闭包,我们可以创建一个函数来帮助我们生成这些数字。

    首先,我将建立一个新函数,并将其命名为GiveMeEms。 此函数有一个参数(像素)。 这是我们要转换为Ems的像素值。 在函数内部,我们有一个名为baseValue的变量。 我将其设置为16,因为大多数浏览器的基本字体大小为16。 然后,我们建立了一个内部函数doTheMath。 在doTheMath内部,我们将简单地返回pixel / baseValue。

    看到这里,我们要获取该pixels参数,并在内部函数中使用它,然后获取变量基值,并在内部函数中使用它。 最后关闭所有内容,我们返回doTheMath。 现在,我们可以设置一系列变量,调用giveMeEms和不同的像素大小,并获取返回值。 因此,我将设置var smallSize = GiveMeEms。

    在这里,我将传递(12),所以我正在寻找等于12个像素的Em值。 然后var mediumSize = GiveMeEms(18),var largeSize = GiveMeEms(24)。 最后是var xlargeSize = GiveMeEms(32)。

    然后,要在此处实际获得结果,我将创建console.log(“ Small size:”和smallSize)。 我只复制这些。 中,大,特大最后,我需要将小,中,大和超大变量作为函数运行。

    function giveMeEms(pixels){
    var baseValue = 16;
    function doTheMath(){
    return pixels/baseValue;
    }
    return doTheMath;
    }
    var smallSize = giveMeEms(12);
    var mediumSize = giveMeEms(18);
    var largeSize = giveMeEms(24);
    var xlargeSize = giveMeEms(32);
    console.log("Small Size", smallSize())
    console.log("Medium Size", mediumSize())
    console.log("Large Size", largeSize())
    console.log("Extra Large Size", xlargeSize())

    当我保存并在浏览器中运行它时,

    对于每种尺寸,我得到的Em尺寸分别为0.75、1.125、1.5和2。同样,这仅由于封闭而可能。 在这种情况下,这里的闭包既包含此变量的基值,又包含像素的值,即使从技术上讲,giveMeEms函数已经运行,并且当我们在此处调用它时,我们不应该能够获得这些值价值观。

    JavaScript中的闭包是一个有趣的话题,这个特殊的兔子洞比我在这里向您展示的要深入得多。 为了更好地了解闭包的功能强大,可以在哪里使用它们以发挥自己的优势以及何时可能导致问题,您应该查看有关闭包的MDN文章。 它提供了许多示例,以及有关正在发生的事情的更多详细信息,并向您展示了如何在日常代码中使用它们。

    嗨,我叫 Rahul Kumar Mandal 我是全栈开发人员。我写有关JavaScript,NodeJS和reactjs的文章。 并与所有人分享我的世界观,通过在 Twitter Medium中 关注我,加入我的追求

    希望您喜欢这篇有关JavaScript闭包的文章。

    欢迎发表评论并喜欢这篇文章,以便其他人可以在Medium上轻松找到它!

    并感谢您阅读本文,如果您喜欢它,然后与您的朋友和敌人分享。 我会写更多关于JavaScript的, 的NodeJS ,react.js陪在我身边相连。

    翻译自: https://hackernoon.com/closures-in-javascript-learn-the-easy-way-7a7317ce2a07

    java 闭包方法

    展开全文
  • 高质量代码闭包

    2021-03-29 22:23:15
    本文借鉴《编写高质量的C#代码:改善C#程序的157个建议》,算是对自己学习的总结,也希望分享下所学知识~~ 先来看一段代码: List<Action> lists = new List<Action>(); for (int i = 0; i < 5; i++...

    本文借鉴《编写高质量的C#代码:改善C#程序的157个建议》,算是对自己学习的总结,也希望分享下所学知识~~

    先来看一段代码:

    List<Action> lists = new List<Action>();
    
    for (int i = 0; i < 5; i++)
    {
        Action t = () =>
        {
            Console.WriteLine(i.ToString());
        };
        lists.Add(t);
    }
    
    foreach (var item in lists)
    {
        item.Invoke();
    }
    

    我们期望的结果为:0、1、2、3、4。
    但是,实际结果为:5、5、5、5、5。

    为什么没像预期那样执行?
    首先看看生成的IL代码:

     .maxstack  3
      .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action> lists,
               [1] class BetterCode.Program/'<>c__DisplayClass0_0' 'CS$<>8__locals0',
               [2] class [mscorlib]System.Action t,
               [3] int32 V_3,
               [4] bool V_4,
               [5] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class [mscorlib]System.Action> V_5,
               [6] class [mscorlib]System.Action item)
      IL_0000:  nop
      IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action>::.ctor()
      IL_0006:  stloc.0
      IL_0007:  newobj     instance void BetterCode.Program/'<>c__DisplayClass0_0'::.ctor()
      IL_000c:  stloc.1
      IL_000d:  ldloc.1
      IL_000e:  ldc.i4.0
      IL_000f:  stfld      int32 BetterCode.Program/'<>c__DisplayClass0_0'::i
      IL_0014:  br.s       IL_003d
      IL_0016:  nop
      IL_0017:  ldloc.1
      IL_0018:  ldftn      instance void BetterCode.Program/'<>c__DisplayClass0_0'::'<Main>b__0'()
      IL_001e:  newobj     instance void [mscorlib]System.Action::.ctor(object,
                                                                        native int)
      IL_0023:  stloc.2
      IL_0024:  ldloc.0
      IL_0025:  ldloc.2
      IL_0026:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action>::Add(!0)
      IL_002b:  nop
      IL_002c:  nop
      IL_002d:  ldloc.1
      IL_002e:  ldfld      int32 BetterCode.Program/'<>c__DisplayClass0_0'::i
      IL_0033:  stloc.3
      IL_0034:  ldloc.1
      IL_0035:  ldloc.3
      IL_0036:  ldc.i4.1
      IL_0037:  add
      IL_0038:  stfld      int32 BetterCode.Program/'<>c__DisplayClass0_0'::i
      IL_003d:  ldloc.1
      IL_003e:  ldfld      int32 BetterCode.Program/'<>c__DisplayClass0_0'::i
      IL_0043:  ldc.i4.5
      IL_0044:  clt
      IL_0046:  stloc.s    V_4
      IL_0048:  ldloc.s    V_4
      IL_004a:  brtrue.s   IL_0016
      IL_004c:  nop
      IL_004d:  ldloc.0
      IL_004e:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action>::GetEnumerator()
      IL_0053:  stloc.s    V_5
    
    //...省略无用的
    

    在 IL_0007 行,创建了一个对象 <>c__DisplayClass0_0 ,每次循环内部都会为这个类的一个实例变量 i 赋值。
    这就是所谓的闭包对象

    结论:
    如果匿名方法(Lambda表达式)引用了某个局部变量,编译器就会自动将该引用提升到该闭包对象中,即将 for 循环中的 i 变量修改成了闭包对象的公共变量 i 。
    只有这样,代码执行后离开了原局部变量 i 的作用域,包含该闭包对象的作用域也还存在。
    相当于以下代码:

    class TempClass
    {
        public int i;
        public void TempFuc()
        {
            Console.WriteLine(i.ToString());
        }
    }
    
    List<Action> lists = new List<Action>();
    TempClass tempClass = new TempClass();
    for (tempClass.i = 0; tempClass.i < 5; tempClass.i++)
    {
        Action t = tempClass.TempFuc;
        lists.Add(t);
    }
    
    foreach (var item in lists)
    {
        item.Invoke();
    }
    

    如果想要实现不同的效果,可以将闭包对象的产生放在 for 循环内部:

    List<Action> lists = new List<Action>();
    
    for (int i = 0; i < 5; i++)
    {
        int temp = i;
        Action t = () =>
        {
            Console.WriteLine(temp.ToString());
        };
        lists.Add(t);
    }
    
    foreach (var item in lists)
    {
        item.Invoke();
    }
    

    其对应的生成代码就是:

    List<Action> lists = new List<Action>();
    
    for (int i = 0; i < 5; i++)
    {
        TempClass tempClass = new TempClass();
        tempClass.i = i;
        Action t = tempClass.TempFuc;
        lists.Add(t);
    }
    
    foreach (var item in lists)
    {
        item.Invoke();
    }
    
    展开全文
  • js代码中的闭包

    2016-04-30 00:33:00
    作为一个后台开发人员了解前端非常重要,尤其是深处学校实验室做项目时前端把写好的...js的闭包是一个很重要的概念,在编写js代码中经常会被用到的,也是js的特色以及难点。 知道闭包首先得知道js的变量和作用域。...

    作为一个后台开发人员了解前端非常重要,尤其是深处学校实验室做项目时前端把写好的代码直接给你,然后你在修改的时候。我经常做的就是修改前端的代码的HTML和后台交互的部分以及js的ajax部分,之后修改之后也会遇到很多问题,所以只能自己继续修改前端,学习了前端的不少知识。

    js的闭包是一个很重要的概念,在编写js代码中经常会被用到的,也是js的特色以及难点。

    知道闭包首先得知道js的变量和作用域。

    在js中变量不向C/C++/Java中那样,得先定义在使用,js中可以直接使用变量,比如:

    1 n=100;

    当然还有一种方式就是:

    1 num1=10;
    2 var num2=15;

    这两种方式在平时这种情况下看不出来其不同,但是一旦牵扯到了全局变量和局部变量之后就会看到不同之处,js的特殊之处就在于函数内部可以直接读取全局变量:

    1 var num=10;
    2 function readNum(){
    3     alert(num);
    4 }
    5 readNum();

    以上代码可以输出的结果是10,这一点很简单,因为num是全局变量,所以函数可以直接访问。那么函数外部当然就无法访问局部变量:

    1 function readNum(){
    2         var num=10;
    3 }
    4 alert(num);

    很显然这一句会出错。那么在内部定义的时候如果这样定义:

    1 function readNum(){
    2     num=10;
    3 }
    4 alert(num);

    这样的代码就不会出错了,因为在js中使用var修饰的变量是局部的,在函数中不能有外部访问,然而没有使用var修饰的变量是全局的,所有的变量都能访问,那么问题来了,既然外部不能访问用var修饰的局部变量,但是一旦我们有时候需要访问的时候我们怎么办呢?想到的第一个方法就是在函数内部在定义一个函数:

    1
     1 function readNum(){
     2      var num=10;
     3      function alNum(){
     4          alert(num);
     5      }
     6     return alNum;
     7  }
     8 
     9 var useAl=alNum;
    10 useAl();

    这一点和C语言等语言很类似,就第二个函数属于第一个函数内部,对于第二个函数来讲,num这个变量是相对于他全局的,所以可以访问这个变量,所以这个程序输出的值是10,这一点没有问题。那么当我们要访问这个变量的时候就可以将alNum作为返回值来用。这样我们就实现了在外部使用num变量。

    那么!这里的alNum函数就是闭包!然后就是闭包就是使用一个内部函数来给外部一个借口访问内部局部变量,还可以这么理解,就是定义在函数内部的函数,这个函数可以访问到内部的局部变量。

     

    转载于:https://www.cnblogs.com/Summer7C/p/5447940.html

    展开全文
  • 编写代码的原则

    2020-07-16 15:06:45
    编写代码的原则 组件原则:组件内的关系(组内聚合)组件间的关系(组件耦合) 组件聚合方面的原则有以下几个: REP:复用/发布等同原则 CCP:共同闭包原则 CRP:共同复用原则 组件耦合方面的原则有以下几个: ADP:...
  • javascript闭包Closures – many of you JavaScript devs have probably heard this term before. When I started my journey with JavaScript, I encountered closures often. And I think they're one of the most...
  • demo中的代码,需要jquery库文件支持 [code="js"] //闭包特性, //1....//2....定义一个匿名函数--闭包 ... //这里编写插件代码,可以继续使用$作为jquery的别名 /** 定义一个局部变量foo,仅...
  • JavaScript 闭包

    2019-10-03 00:18:29
    我们在编写代码的过程中,一定会遇到多人开发的问题,既然是多人开发,变量的命名就很可能会重复,为了解决这个问题就提出了闭包的概念。通过闭包就可以实现在函数外通过一定条件操作局部变量的目的。 二、组成  ...
  • swift 闭包

    2017-03-07 13:41:17
    闭包是自包含的函数代码块,可以在代码中被传递和使用。swift中的闭包与c和oc中的代码块以及其他一些编程语言中的匿名函数比较相似。 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为包裹常量和变量...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,651
精华内容 13,860
关键字:

编写代码闭包的好处