zoukankan      html  css  js  c++  java
  • js怎么防止变量冲突

    [1]工程师甲编写功能A

    1
    2
    3
    var a = 1;
    var b = 2;
    alert(a+b);//3

    [2]工程师乙添加新功能B

    1
    2
    3
    var a = 2;
    var b = 1;
    alert(a-b);//1

    [3]上一步中,工程师乙在不知情的情况下,定义了同名变量a,产生冲突。于是使用匿名函数将脚本包起来,让变量作用域控制在匿名函数之内。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //功能A
    (function(){
      var a = 1;
      var b = 2;
      alert(a+b);//3
    })();
    //功能B
    (function(){
      var a = 2;
      var b = 1;
      alert(a-b);//1
    })();

    [4]此时有了新需求,网页中加入功能C,且需要用到功能A中的变量b。于是在window作用域下定义一个全局变量,把它作为一个桥梁,完成各匿名函数之间的通信

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //全局变量
    var str;
    //功能A
    (function(){
      var a = 1;
      //将b的值赋给str
      var b = str = 2;
      alert(a+b);//3
    })();
    //功能B
    (function(){
      var a = 2;
      var b = 1;
      alert(a-b);//1
    })();
    //功能C
    (function(){
      //将str的值赋给b
      var b = str;
      alert(b);//2
    })();

    [5]但如果功能C还需要功能A中的变量a呢,这时就需要再定义一个全局变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //全局变量
    var str,str1;
    //功能A
    (function(){
      //将a的值赋给str1
      var a = str1 = 1;
      //将b的值赋给str
      var b = str = 2;
      alert(a+b);//3
    })();
    //功能B
    (function(){
      var a = 2;
      var b = 1;
      alert(a-b);//1
    })();
    //功能C
    (function(){
      //将str1的值赋给a
      var a = str1;
      //将str的值赋给b
      var b = str;
      alert(a*b);//2
    })();

    [6]但随着匿名函数之间需要通信的变量越多,需要的全局变量也就越多。因此需要严格控制全局变量的数量,使用hash对象作为全局变量,可以将需要的变量都作为对象的属性,可以保证全局变量的个数足够少,同时拓展性非常好

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //全局变量
    var GLOBAL = {};
    //功能A
    (function(){
      //将a的值赋给GLOBAL.str1
      var a = GLOBAL.str1 = 1;
      //将b的值赋给GLOBAL.str
      var b = GLOBAL.str = 2;
      alert(a+b);//3
    })();
    //功能B
    (function(){
      var a = 2;
      var b = 1;
      alert(a-b);//1
    })();
    //功能C
    (function(){
      //将GLOBAL.str1的值赋给a
      var a = GLOBAL.str1;
      //将GLOBAL.str的值赋给b
      var b = GLOBAL.str;
      alert(a*b);//2
    })();

    [7]但如果新增功能D,功能D需要和功能B通信,并使用功能B脚本中的变量a,开发功能D的是工程师丁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //全局变量
    var GLOBAL = {};
    //功能A
    (function(){
      //将a的值赋给GLOBAL.str1
      var a = GLOBAL.str1 = 1;
      //将b的值赋给GLOBAL.str
      var b = GLOBAL.str = 2;
      alert(a+b);//3
    })();
    //功能B
    (function(){
      //将a的值赋给GLOBAL.str1
      var a = GLOBAL.str1 = 2;
      var b = 1;
      alert(a-b);//1
    })();
    //功能C
    (function(){
      //将GLOBAL.str1的值赋给a
      var a = GLOBAL.str1;
      //将GLOBAL.str的值赋给b
      var b = GLOBAL.str;
      alert(a*b);//2
    })();
    //功能D
    (function(){
      //将GLOBAL.str1的值赋给a
      var a = GLOBAL.str1;
      alert(a*2);//4
    })();

    [8]由于工程师丁只关心自己的匿名函数和功能B的匿名函数,使用GLOBAL.str却无意中覆盖了功能A中设置的同名变量,导致功能C出错。于是使用命名空间来解决这个问题,在不同的匿名函数下,根据功能声明一个不同的命名空间,然后每个匿名函数中的GLOBAL对象的属性都不要直接挂在GLOBAL对象上,而是挂在此匿名函数的命名空间下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    //全局变量
    var GLOBAL = {};
    //功能A
    (function(){
      GLOBAL.A = {};
      //将a的值赋给GLOBAL.A.str1
      var a = GLOBAL.A.str1 = 1;
      //将b的值赋给GLOBAL.A.str
      var b = GLOBAL.A.str = 2;
      alert(a+b);//3
    })();
    //功能B
    (function(){
      GLOBAL.B = {};
      //将a的值赋给GLOBAL.B.str1
      var a = GLOBAL.B.str1 = 2;
      var b = 1;
      alert(a-b);//1
    })();
    //功能C
    (function(){
      //将GLOBAL.A.str1的值赋给a
      var a = GLOBAL.A.str1;
      //将GLOBAL.A.str的值赋给b
      var b = GLOBAL.A.str;
      alert(a*b);//2
    })();
    //功能D
    (function(){
      //将GLOBAL.B.str1的值赋给a
      var a = GLOBAL.B.str1;
      alert(a*2);//4
    })();

    [9]如果同一个匿名函数中的程序非常复杂,变量名很多,命名空间还可以进一步拓展,生成二级命名空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //以功能A为例
    (function(){
      var a = 1, b = 2;
      GLOBAL.A = {};
      GLOBAL.A.CAT = {};
      GLOBAL.A.DOG = {};
      GLOBAL.A.CAT.name = 'mimi';
      GLOBAL.A.DOG.name = 'xiaobai';
      GLOBAL.A.CAT.move = function(){};
      GLOBAL.A.str1 = a;
      GLOBAL.B.str = b; 
    })();

    [10]因为生成命名空间是个非常常用的功能,进一步将生成命名空间的功能定义成一个函数,方便调用,完整版本改写后的代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    var GLOBAL = {};
    GLOBAL.namespace = function(str){
      var arr = str.split('.');
      var o = GLOBAL;
      var start = 0;
      if(arr[0] == 'GLOBAL'){
        start = 1;
      }else{
        start = 0;
      }
      for(var i = start; i < arr.length; i++){
        o[arr[i]] = o[arr[i]] || {};
        o = o[arr[i]];
      }
    };
    //功能A
    (function(){
      var a = 1;
      var b = 2;
      GLOBAL.namespace('A.CAT');
      GLOBAL.namespace('A.DOG');
      GLOBAL.A.CAT.name = 'mimi';
      GLOBAL.A.DOG.name = 'xiaobai';
      GLOBAL.A.CAT.move = function(){};
      GLOBAL.A.str1 = a;
      GLOBAL.A.str = b; 
      alert(a+b);//3
    })();
    //功能B
    (function(){
      var a = 2;
      var b = 1;
      GLOBAL.namespace('B');
      GLOBAL.B.str1 = a;
      alert(a-b);//1
    })();
    //功能C
    (function(){
      var a = GLOBAL.A.str1;
      var b = GLOBAL.A.str;
      alert(a*b);//2
    })();
    //功能D
    (function(){
      var a = GLOBAL.B.str1;
      alert(a*2);//4
    })();

    [11]代码的冲突问题已经解决了,但可维护性并不强。比如,现在需要让工程师甲去修改功能B。因为工程师甲写的脚本是关于功能A的,他并不知道功能B的脚本情况。为了改善这种局面,需要给代码添加适当的注释。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    var GLOBAL = {};
    GLOBAL.namespace = function(str){
      var arr = str.split('.');
      var o = GLOBAL;
      var start = 0;
      if(arr[0] == 'GLOBAL'){
        start = 1;
      }else{
        start = 0;
      }
      for(var i = start; i < arr.length; i++){
        o[arr[i]] = o[arr[i]] || {};
        o = o[arr[i]];
      }
    };
    /*
    * @method 功能A:实现加法运算
    * @author 工程师甲
    * @connect 1234567
    * @time 2015-01-01
    */
     
    (function(){
      var a = 1;
      var b = 2;
      GLOBAL.namespace('A.CAT');
      GLOBAL.namespace('A.DOG');
      GLOBAL.A.CAT.name = 'mimi';
      GLOBAL.A.DOG.name = 'xiaobai';
      GLOBAL.A.CAT.move = function(){};
      GLOBAL.A.str1 = a;
      GLOBAL.A.str = b; 
      alert(a+b);//3
    })();
    /*
    * @method 功能B:实现减法运算
    * @author 工程师乙
    * @connect 1234567
    * @time 2015-01-01
    */
    (function(){
      var a = 2;
      var b = 1;
      GLOBAL.namespace('B');
      GLOBAL.B.str1 = a;
      alert(a-b);//1
    })();
    /*
    * @method 功能C:实现乘法运算
    * @author 工程师丙
    * @connect 1234567
    * @time 2015-01-01
    */
    (function(){
      var a = GLOBAL.A.str1;
      var b = GLOBAL.A.str;
      alert(a*b);//2
    })();
    /*
    * @method 功能D:实现乘2运算
    * @author 工程师丁
    * @connect 1234567
    * @time 2015-01-01
    */
    (function(){
      var a = GLOBAL.B.str1;
      alert(a*2);//4
    })();
    (function(){
               var m = 0;
               var n = 1;
    
               function getName(){
                      return m;
               }
    
               function setName(name){
                      m=name;
               }
    
    
              Window['mySpace']=getName();
    
    
    })();
    
    mySpace();
    //jquery就是这么干的
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    方法2:

    var mainSpace = window.nameSpace ||{};
    mainSpace.name = 'main';
    mainSpace.type='page';
    mainSpace.sayHello = function(name){
        return 'hello'+(name||this.name);
    };
    
    mainSpace.sayHello();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方法3:

    //定义类
    var mainSpace = window.mainSpace || {};
    
    mainSpace.Person = function(){
         this.name = 'John';
    } 
    
    mainSpace.Person.prototype.getName = function(_name){
        return 'Hello '+(_name || this.name);
    };
    
    //调用
    var p1= new mainSpace.Person();
    p1.getName();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其它:
    通过JSON对象创建Object

    /*
    Object
    */
    var NameSpace = window.NameSpace || {};
    NameSpace.Hello = {
        name: 'world'
      , sayHello: function(_name) {
        return 'Hello ' + (_name || this.name);
      }
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    调用

    NameSpace.Hello.sayHello('JS');
    > Hello JS;
    • 1
    • 2
    • 1
    • 2

    这种写法比较紧凑,缺点是所有变量都必须声明为公有(public)的,导致所有对这些变量的引用都需要加this指示作用域,写法也略有冗余。

    通过闭包(Closure)和Object实现

    在闭包中声明好所有变量和方法,并通过一个JSON Object返回公有接口:

    var NameSpace = window.NameSpace || {};
    NameSpace.Hello = (function() {
      //待返回的公有对象
      var self = {};
      //私有变量或方法
      var name = 'world';
      //公有方法或变量
      self.sayHello = function(_name) {
        return 'Hello ' + (_name || name);
      };
      //返回的公有对象
      return self;
    }());
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Object和闭包的改进型写法

    上个例子在内部对公有方法的调用也需要添加self,如:self.sayHello(); 这里可以最后再返回所有公有接口(方法/变量)的JSON对象。

    var NameSpace = window.NameSpace || {};
    NameSpace.Hello = (function() {
      var name = 'world';
      var sayHello = function(_name) {
        return 'Hello ' + (_name || name);
      };
      return {
        sayHello: sayHello
      };
    }());
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Function的简洁写法

    这是一种比较简洁的实现,结构紧凑,通过function实例,且调用时无需实例化(new),方案来自stackoverflow:

    var NameSpace = window.NameSpace || {};
    NameSpace.Hello = new function() {
      var self = this;
      var name = 'world';
      self.sayHello = function(_name) {
        return 'Hello ' + (_name || name);
      };
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    调用

    NameSpace.Hello.sayHello();

    让javascript不再冲突,需要

      •   [1]避免全局变量的泛滥
      •   [2]合理使用命名空间
      •   [3]为代码添加必要的注释
  • 相关阅读:
    Python基础-EMS系统
    python基础-数据结构及数据读取操作
    python基础-猜数游戏
    python基础-质数判断及优化
    利用5次shift漏洞破解win7密码
    python基础-水仙花数判断
    pickle,json ;random,shelve
    block母版继承,include模板导入,inclusion_tag自定义模板
    多道技术,阻塞非阻塞,同步异步,udp,tcp,孤儿僵尸进程
    深度广度继承,抽象类接口,绑定方法,@propertry,继承封装接口多态鸭子类型关系,组合
  • 原文地址:https://www.cnblogs.com/YangJieCheng/p/7192970.html
Copyright © 2011-2022 走看看