写C或者JAVA习惯的人写JavaScript时可能会发现JavaScript并没有命名空间这一概念,当然如果没有接触过命名空间的程序猿(比如写js,PHP,Python)也可能对命名空间不关注或者不重视。这样的情况普遍存在,见过不少人写JavaScript时直接就全局变量的写,如:
1
2
3
4
5
6
7
|
function
a(){
}
function
b(){
}
|
什么是命名空间呢?语言使用的一种代码组织的形式 通过名称空间来分类,区别不同的代码功能 。无论项目大小,如果一开始不严格按照命名空间来编写程序,当你写到上万行JavaScript程序的时候,我相信你一定会后悔你的object或者function命名已经很混乱了。所以建议童鞋们一开始就要养成命名空间的习惯,比如你要开发一个项目,功能可能如下:
那么你可以这样来命名:
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
config = {};
// 前台
config.front = {};
// 后台
config.admin = {};
// 后台数据
config.admin.data = {};
// 后台模块
config.admin.module = {};
// 后台颜色模块
config.admin.module.color = {};
// 后台图片模块
config.admin.module.images = {};
// 后台搜索模块
config.admin.module.search = {};
// 给后台颜色模块加背景颜色改变功能
config.admin.module.color.changeBgColor =
function
(color) {
document.body.style.background = color;
};
// 可以这么调用
config.admin.module.color.changeBgColor(
'#F30'
);
|
我们看看这段object在内存中的结构
但是,以上声明命名空间的方式看起来不直观,我们来一个比较直观的结构化命名方式:
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
|
// 配置
var
config = {
// 前台
front : {},
// 后台
admin : {
// 数据层
data : {},
// 模块层
module : {
// 颜色模块
color : {
// 背景颜色改变功能
changeBgColor :
function
(color){
document.body.style.background = color;
},
// 前景颜色改变功能
changeFnColor :
function
(color){
document.body.style.color = color;
}
},
// 图片模块
images : {
},
// 搜索模块
search : {
}
}
}
};
// 可以这么调用
config.admin.module.color.changeBgColor(
'#F30'
);
|
以上的声明方式就把结构化很好的呈现出来了,利用命名空间非常方便的管理维护拓展程序,当多人开发或者JavaScript代码写的数量巨大时不用担心命名冲突的问题。我们也可以写一个命名空间的功能,省去以上复杂的声明方式。比如以上例子实际上我只是暂时用到config.admin.module.color.changeBgColor这个功能,那么我就需要先定义config,接着admin,然后module,最后是color.changeBgColor,比较繁琐,于是我们可以写一个命名空间注册的功能,直接注册就能用:
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
|
// 命名空间注册函数
var
namespace = {
reg :
function
(s){
var
arr = s.split(
'.'
);
var
namespace = window;
for
(
var
i=0,k=arr.length;i<k;i++){
if
(
typeof
namespace[arr[i]] ==
'undefined'
){
namespace[arr[i]] = {};
}
namespace = namespace[arr[i]];
}
},
del :
function
(s){
var
arr = s.split(
'.'
);
var
namespace = window;
for
(
var
i=0,k=arr.length;i<k;i++){
if
(
typeof
namespace[arr[i]] ==
'undefined'
){
return
;
}
else
if
( k == i+1 ){
delete
namespace[arr[i]];
return
;
}
else
{
namespace = namespace[arr[i]];
}
}
}
};
|
可以这样注册命名空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 先注册命名空间
namespace.reg(
'config.admin.module.color'
);
// 添加功能
config.admin.module.color.changeBgColor =
function
(color){
document.body.style.background = color;
};
// 调用功能
config.admin.module.color.changeBgColor(
'#F30'
);
// 删除命名空间
namespace.del(
'config.admin.module.color'
);
|
命名空间没有唯一规则,只有根据每个项目以及项目负责人对程序的分析然后给出一定命名规则,比如有些项目根据功能命名空间,有些项目根据负责人名命名空间等等。但无论采用哪种方式,合理的命名空间在你应对大项目时多人合作时不会因为命名冲突而重构。因此你的站点中的js文件将有一篇是第一位引入的namespace.js,它定义了这个项目所有的命名空间与管理。
浅谈js命名空间管理
在C# 和 Java里面我们如果想使用哪一个功能类就要引用相应的命名空间。
如C#里面有个System.Web.UI库,我们就要用using System.Web.UI;,之后我们就可以用到ScriptManager这个类了。
js里面其实是不纯在所谓的命名空间的,只是以对象字面量的方式展示出这种效果。
js实现以上的效果通过以下代码:
var System={
Web:{
UI:{
ScriptManager:{}
}
}
};
这种方式感觉比较麻烦,还是习惯通过System.Web.UI这种方式来注册一个命名空间 NameSpace.Register("System.Web.UI"),我们只需要动态的创建对象就能实现。
动态创建对象我们可以通过 两种方法:1.window 对象实现 2.eval实现。
下面就介绍两种实现方式:
1.window 对象实现 :
我们知道定义一个对象可以这样,window['System']={}; System['Web']={} ;System.Web['UI']={};
其实这样就简单了,我们实现动态创建对象只需要拆分字符串创建对应的对象,代码如下:
var NameSpace = { Register: function () { // body... var arg = arguments[0]; var arr = arg.split('.'); var context = window; for (var i = 0; i < arr.length; i++) { var str = arr[i]; if (!context[str]) { context[str] = {}; } context = context[str]; }; } }
2.eval实现:
var NameSpace = { Register: function () { // body... var arg = arguments[0]; var arr = arg.split('.'); var str = ''; for (var i = 0; i < arr.length; i++) { str = i == 0 ? arr[i] : (str + '.' + arr[i]); var sval = " if(typeof " + str + "=='undefined' ) { " + str + "= new Object(); } "; eval(sval) ; }; } }
这种是通过动态执行js字符串的方式,其实是将字符转换成代后执行而已,代码就没啥难度了。
我们就可以直接通过 NameSpace.Register("System.Web.UI")注册对象,然后 System.Web.UI.dom={ method:function(){}}这样扩展一些方法。
扩展想法:既然对象已经创建出来了,我又有了个想法。我觉得可以模仿模块化编程,进行进一步改造。可以扩展类似于以下的函数:
define("dom.utility", function(){
return {
test :function(){
}
}
})
或者
define("dom.utility",{ test :function(){
})
调用的时候我们就直接用dom.utility.test()这种方式;
实现这个define函数的思路:对象的属性拷贝,例如:将test属性加到dom.utility对象下面。
大家可以自己先写一个试试看,可以把代码贴到评论里面方便大家交流学习,下一篇我会贴出源码。