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]为代码添加必要的注释
js怎么防止变量冲突的更多相关文章
- js学习之变量、作用域和内存问题
js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...
- js对象私有变量公有变量问题
0 js对象私有变量公有变量问题5 小弟初学JS面向对象编程 现有一问题 请教各位大虾: Person=function (){ //私有变量定义 var name; vae age; var Ale ...
- js 函数和变量的提升
js 函数和变量的提升 1. 函数的作用域: js中 ,函数的作用域为函数,而不是大括号. var hei = 123;if(true){ hei = 456;}console.log(hei);// ...
- JS函数和变量
JS函数和变量 函数: 函数是由事件或者当它被调用时执行的可重复使用的代码块. 是一个独立的代码块,实现特定功能模块. 函数他不进行调用触发的话,不会自己主动执行. 像ATM机一样,不去取钱的话不会 ...
- Js中执行变量中的命令语句,也就是所谓的宏替换(很实用的例子)
Js中执行变量中的命令语句,也就是所谓的宏替换(很实用的例子) 由其做动态编程时非常有用,必须符合js中的语法,用eval能够执行. var aaa="alert('这是变量中的语句')&q ...
- Javascript开发技巧(JS中的变量、运算符、分支结构、循环结构)
一.Js简介和入门 继续跟进JS开发的相关教程. <!-- [使用JS的三种方式] 1.HTML标签中内嵌JS(不提倡使用): 示例:<button onclick="javas ...
- 从零开始的JS生活(一)——JS简介、变量及基本结构
本K在经过三个静态站制作的狂风暴雨之后,终于开始了JavaScript的学习.作为一只从来没有正儿八经接受过计算机语言的小白,居然能够跟上浩哥的课程进度,我的内心都被我的才智震惊到了,果然本K是天生丽 ...
- JavaScript 基础——使用js的三种方式,js中的变量,js中的输出语句,js中的运算符;js中的分支结构
JavaScript 1.是什么:基于浏览器 基于(面向)对象 事件驱动 脚本语言 2.作用:表单验证,减轻服务器压力 添加野面动画效果 动态更改页面内容 Ajax网络请求 () 3.组成部分:ECM ...
- JS中的变量和输入输出
一.使用JS的三种方式 1.在HTML标签中,直接内嵌JS(并不提倡使用) <button onclick="alert('点你咋地')">点我</button& ...
随机推荐
- eclipse环境下基于已构建struts2项目整合spring+hibernate
本文是基于已构建的struts2项目基础上整合 spring+hibernate,若读者还不熟悉struts2项目,请先阅读 eclipse环境下基于tomcat-7.0.82构建struts2项目 ...
- String的Intern方法
jdk6 和 jdk7 下 intern 的区别 相信很多 JAVA 程序员都做做类似 String s = new String("abc")这个语句创建了几个对象的题目. 这种 ...
- 照虎画猫写自己的Spring——自定义注解
Fairy已经实现的功能 读取XML格式配置文件,解析得到Bean 读取JSON格式配置文件,解析得到Bean 基于XML配置的依赖注入 所以,理所当然,今天该实现基于注解的依赖注入了. 基于XML配 ...
- 匿名HTTP透明HTTP高匿HTTP区别
透明代理的意思是客户端根本不需要知道有代理服务器的存在,但是它传送的仍然是真实的IP.你要想隐藏的话,不要用这个. 普通匿名代理能隐藏客户机的真实IP,但会改变我们的请求信息,服务器端有可能会认为我们 ...
- 熟悉Objective—C
1.oc使用消息结构而非函数调用 使用消息结构的语言,运行时所应执行的代码由运行环境来决定,而是用函数调用的语言,则由编译器决定.函数调用:如果调用的函数是多态的,那么在运行时就要按照“虚方法表”来查 ...
- java自动生成entity文件
网上关于自动生成entity文件的代码很多,看了很多代码后,在先辈们的基础上再完善一些功能(指定多个表,全部表). 为了使用方便所以把两个类写在一个java文件中,所以大家可以直接拿这个java文件, ...
- window下phpstudy的nginx配置虚拟主机
由于很长时间没有配置Apache,虽然说知道怎么配置nginx,但是还是花费了一些时间这次记下来下次直接用 在其他选项文件菜单中->打开配置文件->选择vhosts-conf nginx的 ...
- 数据结构与算法(C/C++版)【串】
第四章<串.数组> (一)串 数据结构中提到的串,即字符串,由 n 个字符组成的一个整体( n >= 0 ).这 n 个字符可以由字母.数字或者其他字符组成.例如,S = &qu ...
- 【luogu P1471】方差
https://www.luogu.org/problem/show?pid=1471 一眼就能看出是线段树/树状数组题目了. 求平均不用说,线段树/树状数组维护区间和即可. 方差怎么求?先变换下方差 ...
- ABAP CDS Table Function介绍与示例
Core data services(以下简称CDS)可以指两样东西,一个是HANA CDS,一个是ABAP CDS. 如我们所知,HANA CDS只支持HANA数据库,ABAP CDS理论上支持多种 ...