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

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

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

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

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

//功能A
(function(){
  var a = 1;
  var b = 2;
  alert(a+b);//
})();
//功能B
(function(){
  var a = 2;
  var b = 1;
  alert(a-b);//
})();

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

//全局变量
var str;
//功能A
(function(){
  var a = 1;
  //将b的值赋给str
  var b = str = 2;
  alert(a+b);//
})();
//功能B
(function(){
  var a = 2;
  var b = 1;
  alert(a-b);//
})();
//功能C
(function(){
  //将str的值赋给b
  var b = str;
  alert(b);//
})();

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

//全局变量
var str,str1;
//功能A
(function(){
  //将a的值赋给str1
  var a = str1 = 1;
  //将b的值赋给str
  var b = str = 2;
  alert(a+b);//
})();
//功能B
(function(){
  var a = 2;
  var b = 1;
  alert(a-b);//
})();
//功能C
(function(){
  //将str1的值赋给a
  var a = str1;
  //将str的值赋给b
  var b = str;
  alert(a*b);//
})();

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

//全局变量
var GLOBAL = {};
//功能A
(function(){
  //将a的值赋给GLOBAL.str1
  var a = GLOBAL.str1 = 1;
  //将b的值赋给GLOBAL.str
  var b = GLOBAL.str = 2;
  alert(a+b);//
})();
//功能B
(function(){
  var a = 2;
  var b = 1;
  alert(a-b);//
})();
//功能C
(function(){
  //将GLOBAL.str1的值赋给a
  var a = GLOBAL.str1;
  //将GLOBAL.str的值赋给b
  var b = GLOBAL.str;
  alert(a*b);//
})();

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

//全局变量
var GLOBAL = {};
//功能A
(function(){
  //将a的值赋给GLOBAL.str1
  var a = GLOBAL.str1 = 1;
  //将b的值赋给GLOBAL.str
  var b = GLOBAL.str = 2;
  alert(a+b);//
})();
//功能B
(function(){
  //将a的值赋给GLOBAL.str1
  var a = GLOBAL.str1 = 2;
  var b = 1;
  alert(a-b);//
})();
//功能C
(function(){
  //将GLOBAL.str1的值赋给a
  var a = GLOBAL.str1;
  //将GLOBAL.str的值赋给b
  var b = GLOBAL.str;
  alert(a*b);//
})();
//功能D
(function(){
  //将GLOBAL.str1的值赋给a
  var a = GLOBAL.str1;
  alert(a*2);//
})();

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

//全局变量
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);//
})();
//功能B
(function(){
  GLOBAL.B = {};
  //将a的值赋给GLOBAL.B.str1
  var a = GLOBAL.B.str1 = 2;
  var b = 1;
  alert(a-b);//
})();
//功能C
(function(){
  //将GLOBAL.A.str1的值赋给a
  var a = GLOBAL.A.str1;
  //将GLOBAL.A.str的值赋给b
  var b = GLOBAL.A.str;
  alert(a*b);//
})();
//功能D
(function(){
  //将GLOBAL.B.str1的值赋给a
  var a = GLOBAL.B.str1;
  alert(a*2);//
})();

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

//以功能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]因为生成命名空间是个非常常用的功能,进一步将生成命名空间的功能定义成一个函数,方便调用,完整版本改写后的代码如下

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);//
})();
//功能B
(function(){
  var a = 2;
  var b = 1;
  GLOBAL.namespace('B');
  GLOBAL.B.str1 = a;
  alert(a-b);//
})();
//功能C
(function(){
  var a = GLOBAL.A.str1;
  var b = GLOBAL.A.str;
  alert(a*b);//
})();
//功能D
(function(){
  var a = GLOBAL.B.str1;
  alert(a*2);//
})();

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

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);//
})();
/*
* @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);//
})();
/*
* @method 功能C:实现乘法运算
* @author 工程师丙
* @connect 1234567
* @time 2015-01-01
*/
(function(){
  var a = GLOBAL.A.str1;
  var b = GLOBAL.A.str;
  alert(a*b);//
})();
/*
* @method 功能D:实现乘2运算
* @author 工程师丁
* @connect 1234567
* @time 2015-01-01
*/
(function(){
  var a = GLOBAL.B.str1;
  alert(a*2);//
})();

让javascript不再冲突,需要

  [1]避免全局变量的泛滥

  [2]合理使用命名空间

  [3]为代码添加必要的注释

如何避免javascript中的冲突的更多相关文章

  1. javascript中变量命名冲突的问题

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. JavaScript 中的数据类型

    Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...

  3. 深入理解JavaScript中创建对象模式的演变(原型)

    深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...

  4. 浅谈JavaScript中的this

    引言 JavaScript 是一种脚本语言,因此被很多人认为是简单易学的.然而情况恰恰相反,JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.本文仅采撷其中的一例:JavaScri ...

  5. JavaScript中的逗号运算符

    JavaScript逗号运算符  阅读本文的前提,明确表达式.短语.运算符.运算数这几个概念. 所谓表达式,就是一个JavaScript的“短语”,JavaScript解释器可以计算它,从而生成一个值 ...

  6. 深入浅出 JavaScript 中的 this

    在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.一般在编译期确定下来,或称为编译期绑定.而在 JavaScript 中,this 是动态绑定,或称为运行期绑定的 ...

  7. [转]Javascript中的自执行函数表达式

    [转]Javascript中的自执行函数表达式 本文转载自:http://www.ghugo.com/javascript-auto-run-function/ 以下是正文: Posted on 20 ...

  8. 深入理解javascript中的立即执行函数(function(){…})()

    投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...

  9. 【转】深入浅出 JavaScript 中的 this

    Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.一般在编译期确定下来,或称为编译期绑定.而在 JavaScript 中,this 是动态绑定,或称为运行期绑定的,这 ...

随机推荐

  1. Usart的单线半双工模式(stm32F10x系列)

    这两天折腾CTS/RTS硬件流控,看到说232协议的CTS/RTS只是用来做半双工换向使用的.正好手头上有块stm32的板子,看了看stm32的Usart,竟然发现支持的是单线半双工.232里面毕竟4 ...

  2. 一步一步安装hive

    安装hive 1.下载hive-0.11.0.tar.gz,解压; 2.下载mysql-connector-java-5.1.29-bin.jar并放到hive/lib/下: 3.配置hive/con ...

  3. 我的iOS之路2

    第一篇果然没人看呢...好吧...那就当笔记做吧...第一篇主要写的是生成了一个helloworld,可能也是和别人撞了,所以有点厌烦,连名字都改掉吧 好,开始写第二篇 之前做第一个应用程序的时候没有 ...

  4. [转] How to Show Usual Winform as View in XAF

    How to Show Usual Winform as View in XAF http://www.codeproject.com/Tips/464188/How-to-Show-Usual-Wi ...

  5. Eclipse配置PHP及自动提示功能

    Eclipse是一个开发工具,具有强大的插件功能,虽然用于Java理所当然,但为PHP所用,也为尝不可.虽然我一直用的是notepad,但发现开发工具也可以省去一些不必要的记忆. 言归正传,下面就来实 ...

  6. Erlang在Windows上开发环境搭建全过程讲解目录

    我会按照下面的列表来一步一步讲解,在windows来开发Erlang所用到的一些工具,和知识.我会不停的添加和修正. Erlang运行时环境 Erlang开发工具选择 Rebar来构建,编译,测试,发 ...

  7. CSS浮动(float,clear)通俗讲解

    首先要知道,div是块级元素,在页面中独占一行,自上而下排列,也就是传说中的流.如下图: 可以看出,即使div1的宽度很小,页面中一行可以容下div1和div2,div2也不会排在div1后边,因为d ...

  8. XML dom

    将文件解析为文档 三步过程 为了使用 XML 文件中的信息,必须解析文件以创建一个 Document 对象. Document 对象是一个接口,因而不能直接将它实例化:一般情况下,应用程序会相应使用一 ...

  9. Eclipse无法启动错误之Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini)

    悲剧,在安装Android Build Tools时,提醒需要关闭Eclipse进行安装,于是我在Tools安装完成后重启了Eclipse.但是Eclipse却无法启动,在log中有如下提示: Una ...

  10. java Map及Map.Entry详解

    Map是java中的接口,Map.Entry是Map的一个内部接口. Map提供了一些常用方法,如keySet().entrySet()等方法. keySet()方法返回值是Map中key值的集合:e ...