zoukankan      html  css  js  c++  java
  • 匿名函数和闭包(下)

    http://edu.51cto.com/lesson/id-6390.html

    本文主要讲匿名函数中的私有化(私有作用域,私有变量)的问题

    一、模仿块级作用域   

    1.块级作用域(也叫私有作用域)

    function box(){

    for(var i=0; i<5; i++){   //for语句为块级作用域(但是在这里不是块级作用域,因为JS没这个东西)

    }

    alert(i);

    }

    box(); //输出5  说明for语句里用完之后 没有销毁

    function box(){

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

    }

    var i;             //就算重新声明,也不会影响之前声明初始化的数据  这里若声明并初始化 var i=1000,则最后输出的是1000

    alert(i);

    }

    box(); //输出5  

    以上两个例子说明,javascript没有块级作用域。if(){} for(){}等没有作用域,如果有,出了这个范围 i 就应该呗销毁了。就算重新声明同一个变量也不会改变它的值。

    js不会提醒你是否多次声明了同一个变量。遇到这种情况,它只会对后续的声明视而不见(如果初始化了,当然还会执行的)。使用模仿块级作用域可避免这个问题。

    2.使用块级作用域(私有作用域)

    (达到目的:上面的例子,除了for语句,i 就销毁掉了)

    function box(){

    (function(){     //包含自我执行的匿名函数,就可以实现私有作用域

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

    alert(i); //输出5次 0 1 2 3 4

    }//这里面用了a b c等变量

    })();  //出了这个私有作用域,变量立即被销毁  a b c被销毁

    //这里可以继续使用a b c等变量,和上面的a b c完全没有联系

    alert(i); //这里就不认识了 not defined 

    }

    box();

    使用了块级作用域(私用作用域)后,匿名函数中定义的任何变量,都会在执行结束时被销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说,我们都应该尽可能少向全局作用域中添加变量和函数。在大项目中,多人开发的时候,过多的全局变量和函数容易导致命名冲突,引起灾难性的后果。如果采用块级作用域(私有作用域),每个开发者既可以使用自己的变量,又不比担心搞乱全局作用域。

    我们经常看到js文件(用jQUery写的)这样写

    (function($) {  

    这里是我们的逻辑。这里可以形成块级作用域,这里定义的任何变量,和方法。而这些变量和方法,在全局作用域中是访问不到的。私有化,保护局部变量。

    })(jQuery);

    这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。这句话理解如下:

    程序1

    var age=100;

    alert(age);//输出100
    age=null;

    alert(age);//输出null

    程序2

    (function(){

    //这里就是全局的私有作用域

    var age=100;

    alert(age);

    })(); //页面加载,自行执行函数,输出100

    alert(age);// age is not defined 即,外部访问不到私有作用域里的age,这里就不用手动添加age=null,age就会自动销毁。

    在全局作用域中使用块级作用域可以减少闭包占用的内存问题,因为没有指向匿名函数的引用,只要函数执行完毕,就可以立即销毁其作用域链了。

    3.私有变量

    javascript没有私有属性的概念,所有的对象属性都是公有的。不过,却有一个私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,因为不能再函数外部访问这些变量。

    function box(){

    var age=100;  //私有变量,外部无法访问

    }

    function Box(){

    this.age = 100; //属性  下面能box.age可以正确输出,说明是公有的

    this.run = function(){  //方法   下面能box.run可以正确输出,说明是公有的

    return '运行中';

    }

    }

    var box=new Box();

    alert(box.age);//输出 100  

    alert(box.run());//输出 运行中

    而通过函数内部创建一个闭包,那么闭包通过自己的作用域也可以访问这些变量,利用这一点,可以创建用于访问私有变量的公有方法。

    function Box(){

    var age=100;  //私有变量

    function run(){  //私有函数

     return'运行中';

    }

    this.publicGo= function(){   //对外可见的公共接口,特权方法

    return age+run();

    };

    }

    var box = new Box();

    alert(box.publicGo());

    //通过构造函数传参 来访问私有变量

    function Box(value){

    var user=value;  //私有变量

    this.getUser=function(){

      return user;

    };

    this.setUser= function(){

      user=value;

    }

    }

    var box = new Box('lee');

    alert(box.getUser());  //输出lee

    box.setUser('ooo');  //重新赋值

    alert(box.getUser());  //输出ooo

    但是对象的方法,在多次调用的时候,会多次创建。可以使用静态私有变量来避免这个问题。

    静态私有变量 

    通过块级作用域中定义私有变量或函数,同样可以查ungjianduiwai公共的特权方法。

    //

    (function(){

    var user ='' // 私有变量

    //function Box(){}  //构造函数,但是在函数里面写构造函数,不支持,因为私有作用域里的函数,外部无法访问

    Box=function(value){

    user=value;

    }; //全局,构造函数   里面没有var 就说明是全局的

    Box.prototype.getUser = function(){ //使用prototype导致方法共享了,而user变成了静态属性。

    return user;

    };

    Box.prototype.setUser= function(value){

      use=value;

    }

    })();

    var box = new Box('lee');//第一次实例化

    alert(box.getUser());   //输出lee

    var box2 = new Box('kkk');//第二次实例化

    alert(box.getUser());  //输出kkk  实现了共享

    box2. setUser('OOO');

    alert(box.getUser()); //输出OOO 实现了共享

    4.模块模式

    之前采用的都是构造函数的方式来创建私有变量和特权方法,那么对象字面量方式就采用模块模式来创建。这里采用对象字面两方式来创建私有变量和特权方法。

    什么叫单例,就是永远只实例化一次,其实就是字面量声明方式

    var box={  //第一次实例化,无法第二次实例化,那么就是单例

    user :'lee',

    run : function(){

     return '行中';

    };

    //字面量方式 私有化变量和函数

    var box = function(){

    var age=100; //私有变量

    function run(){  //私有函数

     return'运行中';

    }

    return {  //直接返回对象

      go:function(){    //对外公共借口的特权方法

        return age+run();

        }

    };

    }();//自我执行的函数

    alert(box.go());  //输出 100运行中

    上面直接返回对象的例子也可以这么写

    var box = function(){

    var age=100; //私有变量

    function run(){  //私有函数

     return'运行中';

    }

    var obj= {  //直接返回对象

      go:function(){    //对外公共借口的特权方法

        return age+run();

    }

    };

    return obj;

    }();//自我执行的函数

    alert(box.go());  //输出 100 运行中

    字面量的对象声明,其实在设计模式中可以看作是一种单例模式,所谓单例模式,就是永远保持对象的一个实例。

    增强的模块模式,这种模式适合返回自定义对象,也就是构造函数

    //之前的两个例子都是返回的{}  也就是object,如果想返回自定义的呢?例如Desk

    function Desk(){};

    var box = function(){

    var age = 100;

    function = run(){

      return'运行中';

    }

    var desk = new Desk();

    desk.go = function(){

      return age+run();

    }

    return desk;

    }();

    alert(box.go());

  • 相关阅读:
    关于 Bellman-Ford 与 Floyd 算法的一点感想
    中途相遇法 解决 超大背包问题 pack
    具体一些的博弈论 sqrstone
    SG函数学习总结
    mc
    string
    积木大赛
    pta l3-20(至多删三个字符)
    pta l3-7(天梯地图)
    ucore-lab1-练习2report
  • 原文地址:https://www.cnblogs.com/mabelstyle/p/3716681.html
Copyright © 2011-2022 走看看