本文为阅读《JavaScript设计模式》一书后总结部分内容而得,其中代码示例皆来源于该书。
单体的功能
避免在代码复杂的项目中,所创建的全区变量间互相冲突,比如已经有了一个A属性,在之后为了其他功能,又创建了一个同名的A属性。单体为我们提供了一个命名空间,比如有了单体之后,我在NameSpace空间中创建了一个A,又在NameSpace2控件中创建了一个A,NameSpace.A与NameSpace2.A并不冲突。还有很好的一点,单体只会实例化一次。
简单的单体
//定义单体,假设我们已经创建好了一个空的对象字面量MyNamespace作为命名空间
MyNamespace.Singleton = {
constant_1: true,
constant_2: 10,
method1: function() {},
method2: function() {},
init: function() {}
}
//调用单体内变量
MyNamespace.Singleton.init();
存在私有成员的单体
有的时候,我们并不希望有人对单体内的一些成员进行操作,这时候就要通过闭包来定义私有成员。
//定义单体
MyNamespace.Singleton = (function() {
var privateMember1 = "1";
function privateFunction() { ... };
return{
publicMember: "2",
publicFunction: function() { ... }
}
})();
//调用单体内共有成员
MyNamespace.Singleton.publicFunction();
通常有经验的程序员会在立即执行函数处加上(),以明确这是个立即执行函数。如function A(){}()写为(function A(){})().
惰性实例化
以上单体有一个缺陷,就是在脚本加载时就会当即被创建。如果项目有大量单体需要加载,则初始化所需时间会让人崩溃吧。
所以,我们要想办法,让单体延迟创建,并非脚本加载就创建,而是当我们需要调用单体内的成员时,再创建单体。
创建惰性单体需要以下操作:
-
将单体内容通过constructor方法括起来
-
创建一个私有属性,来返回constructor方法
举例:
//定义单体
MyNamespace.Singleton = (function() {
var uniqueInstance;
function constructor() {
var privateMember1 = "1";
function privateFunction() { ... };
return{
publicMember: "2",
publicFunction: function() { ... }
}
}
return{
getInstance: function() {
if (!uniqueInstance) {
uniqueInstance = constructor();
}
return uniqueInstance;
}
}
})();
//调用单体内共有成员
MyNamespace.Singleton.getInstance().publicFunction();
单体中的分支
当我们再不同情况下,需要具有不同的成员的单体时,使用分支。
例子:
MyNamespace.Singleton = (function() {
var objectA = {
method1: function() {
...
},
method2: function() {
...
}
};
var objectB = {
method1: function() {
...
},
method2: function() {
...
}
};
return (sonmeCondition)?objectA:objectB;
})();
单体的弊端
会导致不同模块间的强耦合,比如在同一个单体中的不同成员可能会用在不同模块中,这样在不同模块中必须调用同一个单体中的成员,导致了不同模块间的变量互相之间还具有一定关系,即强耦合。