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& ...
随机推荐
- 【微软大法好】VS Tools for AI全攻略(3)
接着上文,现在我们需要一种穷人的方法来搭建好Azure虚拟机. 思路很简单,因为AI组件的原理其实是传送了script文件和命令上去,那么我们这个虚拟机只要做好了所有的配置,那么我们就可以将它当作深度 ...
- ES 入门之一 安装ElasticSearcha
安装ElasticSearcha 学习ES也有快一个月了,但是学习的时候一直没有总结.以前没有总结是因为感觉不会的很多,现在对ES有一点了解了.索性就从头从安装到使用ES做一个详细的总结,也分享给其他 ...
- DC 辅域转主域
DC 辅域转主域 #dc2辅域 角色转移为主域 #查看 netdom query fsmo ntdsutil roles connections #连接主机dc2 connect to server ...
- 微信小程序爬坑日记
新公司上手小程序.30天,从入门到现在,还没放弃... 虽然小程序发布出来快一年了,爬坑的兄弟们大多把坑都踩平了.而我一直停留在"Hello World"的学习阶段.一来没项目,只 ...
- POJ1273 网络流-->最大流-->模板级别-->最大流常用算法总结
一般预流推进算法: 算法思想: 对容量网络G 的一个预流f,如果存在活跃顶点,则说明该预流不是可行流. 预流推进算法就是要选择活跃顶点,并通过它把一定的流量推进到它的邻接顶点,尽可能将正的赢余减少为0 ...
- XAMPP重要文件目录及配置
一.XAMPP 的安装过程 1:下载XAMPP 的 Linux 版 (1.7.4) http://www.apachefriends.org/en/xampp-linux.html#374 2:安装( ...
- Python操作 Memcache、Redis、RabbitMQ
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...
- CF Round#436 div2
额,这次的题目其实挺智障的.所以通过这次比赛,我也发现了自己是一个智障.... 不说太多,说多是泪... A. Fair Game 题意:给你一个数组,看你能否把它均分为两个所有元素均相同的子数组. ...
- Ubuntu 14.4 Django模型迁移到数据库提示 LookupError: unknown encoding: utf8mb4 解决方法
由于数据库中需要存储emoji表情,因此需要mysql支持utf8mb4,参考前面的文章升级数据库. 但是由于服务器上面的python-mysqldb连接包版本为1.2.3不支持utf8mb4,因此报 ...
- javascript跳跃式前进(3) - 跳入JSON
前言 JSON崛起不是意外,是顺应时代;相当简洁小巧的书写模式及阅读方式; 基础 看这篇文章: JSON知识点汇总_W3SCHOOL 初步进阶 早期的解析仅仅实用eval() ,可是这货太easy给注 ...