zoukankan      html  css  js  c++  java
  • javascript---我对闭包的理解

    一、闭包
           闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成

           如何理解这句话:以一个例子说明;(from MDN)

    function makeFunc({

    var name = "Mozilla";

    function displayName() { alert(name); } return displayName; }

    var myFunc = makeFunc();

    myFunc();

    在这个函数中 myFunc就是闭包,因为:1.它是一个函数,2,它的环境是被创建闭时在作用域中的任何局部变量组成(makeFunc函数的局部环境+全局环境+displayName自己的环境)。

    作用域补充

    http://www.jb51.net/article/30706.htm.
    我的总结为:普通函数的作用域包括全局对象,和自己的活动对象(自己的局部都对象)。当函数销毁后,作用域也被销毁。
    闭包:将创建它的函数(外部函数)的活动对象添加到自己的作用域链中,更重要的是,此种情况下外部函数执行完毕后,其活动对象不会被摧毁,
    因为匿名函数的作用域链仍然在引用这个活动对象(活动对象就会留在内存中)直到该闭包对象被销毁。

     

    二、闭包的应用

    摘自MDN (已经验证,一定要敲一遍)我摘写我学到的部分,该文章中的实用的闭包的例子我觉得不适用,没得必要这么用,而且内存一直被占着。虽然占的内存很小。所以闭包还是要尽量不用。

    https://developer.mozilla.org/cn/docs/Web/JavaScript/Closures

    1.用闭包模拟私有方法

    var Counter = (function()

    { var privateCounter = 0;

    function changeBy(val) { privateCounter += val; }

    return {

    increment: function() { changeBy(1); },

    decrement: function() { changeBy(-1); },

    value: function() { return privateCounter; } } })();

    console.log(Counter.value()); /* logs 0 */

    Counter.increment();

    Counter.increment();

    console.log(Counter.value()); /* logs 2 */

    Counter.decrement();

    console.log(Counter.value()); /* logs 1 */


    这个地方有个重点是,因为函数自执行了,只有一个执行环境,所以内部的匿名函数共享这个环境。
    这样外部无法访问变量privateCounter,和changeBy方法,只能通过返回的对象里的方法来访问,和操作私有变量和私有方法。模拟私有方法。

    2.在循环中创建闭包

       直接例子说话:

    function createFun(){

        var result = new Array();

    for (var i =0;i<10;i++){

       result[i]=function(){

      return i; 

    };

    }

      return result;

    }

    该函数返回的是一个函数数组,每个函数都会返回10,因为每个函数的作用域链中都保存着createFun的活动对象,所以它们引用的都是同一个变量i。此时每个函数都引用着保存变量i的同一个变量,createFun执行后,i=10;

    解决方法

    创建一个匿名函数

    function createFun(){

        var result = new Array();

    for (var i =0;i<10;i++){

       result[i]=function(num){

           return function(){

              return num; 

            }

        }(i);

    }

      return result;

    }

    能行的原因:1.在createFun中立即执行该匿名函数的结果赋给数组,这里的匿名函数有个参数,参数按值传递。所以就将变量i的当前值复制给num,在匿名函数的内部,又创建并返回了一个访问num的闭包。所以result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值。 

    3.模拟bind,函数柯里化

    ECMAScript5中为函数定义了一个原生的bind方法,由于只支持IE9+、Firefox4+、Chrome所以可以自己利用闭包写一个原生的。

    if(!Function.prototype.bind){
    
      //context是函数被绑定的环境
      Function.prototype.bind = function(context){
        var that = this;
        //返回一个闭包,由于闭包能保留外部作用域的引用,在这个例子中就是保留了that     
    return function (){       return that.apply(context,arguments);
        }   } }

    函数柯里化,用于串讲已经设置好了一个或多个参数的函数。

    function curry(fn){
    
      //args保留设置好的的参数
    
      var args = Array.prototype.slice.call(arguments,1);
    
      return function (){

        var innerArgs = Array.prototype.slice.call(arguments);

        var finalArgs = args.concat(innerArgs);
        return fn.apply(null,finalArgs);
      }
    }
    function add(num1,num2){
      return num1+num2;
    }
    var curriedAdd = curry(add,5);
    alert(curriedAdd(4)); // 9
    在程序媛的路上,越走越用劲儿:)
  • 相关阅读:
    Winform中怎样去掉TextBox输入回车时的警告音
    sql server 2000 出现不能执行查询,因为一些文件丢失或未注册”
    c# winform 创建文件,把值写入文件,读取文件里的值,修改文件的值,对文件的创建,写入,修改
    <metro>PlayToReceiver class
    <metro>PlayToReceiver
    <C#>怎样学好Winform
    <C#>怎样学好winform3
    <C#>怎样学好winform4
    <metro>Application Data
    <metro>UI
  • 原文地址:https://www.cnblogs.com/AliceX-J/p/5226297.html
Copyright © 2011-2022 走看看