本文内容
- 命名空间
- 自定义命名空间
命名空间在面向对象编程语言中很常见,用来组织类。多年的工程实践表明,无论是面向对象还是其命名空间都很有效。但是,JavaScript 是基于原型的,本身并不支持面向对象,可我们很想把面向对象实践出来的结果应用到 JavaScript 中,以加强 JavaScript 代码的可维护性。而命名空间是不可缺少的一个环节,当然除此之外,还有用 JavaScript 模拟对象、继承等。
在 JavaScript 编程中,很容易造成命名冲突,如果对局部变量不使用 var 关键字,则 JavaScript 认为是全局变量。试想,要是多人一起开发,更一步,每个人都开发自己的插件,命名冲突就是不可避免的,而最后若想修正这样的错误并不容易。
命名空间
只有一个全局作用域导致的常见错误是命名冲突。在 JavaScript中,这可以通过匿名包装器轻松解决。
(function() {
// 函数创建一个命名空间
window.foo = function() {
// 对外公开的函数,创建了闭包
};
})(); // 立即执行此匿名函数
匿名函数被认为是表达式;因此为了可调用性,它们首先会被执行。
( // 小括号内的函数首先被执行
function() {}
) // 并且返回函数对象
() // 调用上面的执行结果,也就是函数对象
有一些其他的调用函数表达式的方法,比如下面的两种方式语法不同,但是效果一模一样。
// 另外两种方式
+function(){}();
(function(){}());
带“+”的方式,第一次看见是在 ckeditor 中,当时有点惊讶。
推荐使用匿名包装器(自执行的匿名函数)来创建命名空间。这样不仅可以防止命名冲突, 而且有利于程序的模块化。另外,使用全局变量被认为是不好的习惯。这样的代码倾向于产生错误和带来高的维护成本。
自定义命名空间
下面代码,实现自己命名空间机制如下:
myNamespace = {
// 全局对象仅仅存在 reg 函数, 参数为名称空间全路径, 如 myCustomer.control
reg: function (ns) {
var nsArray = ns.split('.');
var sEval = "";
var sNS = "";
for (var i = 0; i < nsArray.length; i++) {
if (i != 0) sNS += ".";
sNS += nsArray[i];
// 依次创建构造命名空间中的对象,
// 如,若 myCustomer 不存在,则创建; 若 myCustomer.control 不存在,则创建……
sEval += "if (typeof(" + sNS + ") == 'undefined') " + sNS + " = { };"
}
if (sEval != "") eval(sEval);
}
}
// 注册自己的命名空间
myNamespace.reg("myCustomer.control");
myNamespace.reg("myCustomer.document");
// 在 myCustomer.control 命名空间里面声明对象 myEditor
myCustomer.control.myEditor = function (id, width, height) {
this.id = id;
this.width = width;
this.height = height;
}
// 为对象 myEditor 添加一个公共方法 show
myCustomer.control.myEditor.prototype.show = function () {
alert("myEditor of control 's id is " + this.id + ", width is " + this.width + " and height is " + this.height);
}
// 演示如何使用类Person
var p = new myCustomer.control.myEditor("txt1", 100, 100);
p.show();
if (typeof (myCustomer.document) != 'undefined') {
alert('myCustomer.document exsit.');
}
else {
alert('myCustomer.document nonexsit.');
}