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& ...
随机推荐
- Vue 浅析与实践
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:曾柏羲 导语 入职接到的第一个需求是实现一个关于K歌实体售卖的ERP系统,管理系统过去做过不少,这次打算换个姿势,基于时下正热但早已不新 ...
- 并发容器之写时拷贝的 List 和 Set
对于一个对象来说,我们为了保证它的并发性,通常会选择使用声明式加锁方式交由我们的 Java 虚拟机来完成自动的加锁和释放锁的操作,例如我们的 synchronized.也会选择使用显式锁机制来主动的控 ...
- 最强离线安装MySQL_8.0.2方法
最强离线安装MySQL_8.0.2方法,一次就能安装成功. 按照此方式,离线安装MySQL五分钟都花不到,节省了大量的宝贵时间. 前戏,假设你已经从MySQL官网中获取了下面这个压缩包: 解压之后变成 ...
- Flex布局学习笔记
任何元素都可以使用Flex布局,包括行内元素 display: flex; display: inline-flex使用Flex布局之后,子元素的float, clear, vertical-alig ...
- win10下Anaconda 2 和 3 共存安装,并切换jupyter notebook和Pycharm中的对应版本
win10下Anaconda 2 和 3 共存安装,并切换jupyter notebook和Pycharm中的对应版本 zoerywzhou@163.com http://www.cnblogs.co ...
- [PHP]Symfony or Laravel 在 console 中结合 Workerman
在web框架的console中,命令不再是直接指定入口文件,如以往 php test.php start,而是类似 php app/console do 的形式. workerman 对命令的解析是 ...
- Python的Web应用框架--Django
一:简介 python的web框架有很多,个人查了一下,有Django.Pylons. Tornado.Bottle和Flask等,其中使用人数最多的是Django,而我学习Django也是因为ope ...
- C/C++筛选法算素数
什么是求素数 )i在2到n-1之间任取一个数,如果n能被整除则不是素数,否则就是素数 普通枚举法: #include <iostream> #include <string> ...
- Hadoop介绍和环境配置
原文:http://www.cnblogs.com/edisonchou/ 一.Hadoop的发展历史 说到Hadoop的起源,不得不说到一个传奇的IT公司-全球IT技术的引领者Google.Goog ...
- memcached 安装以及在php中使用
最近做的一个项目需要不断对数据库内容进行读取和刷新,所以数据库压力很大,用户数目多的时候响应速度也严重受影响. 于是准备将一部分常用数据通过缓存在服务器内存中,减少对数据库的操作来缓解压力(memca ...