1. 常见实现单例
要实现一个标准的单例模式并不复杂,无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。
代码如下:
// 常见单例模式函数
var Singleton = function(name) {
this.name = name;
// 实例创建表示
this.instance = null;
};
Singleton.prototype.getName = function() {
return this.name;
};
// 获取实例方法
Singleton.getInstance = function(name) {
if (!this.instance) {
this.instance = new Singleton(name);
}
return this.instance;
};
var s1 = Singleton.getInstance();
var s2 = Singleton.getInstance();
console.info(s1 === s2); // true
或者:
// 常见单例模式函数
var Singleton = function(name) {
this.name = name;
};
Singleton.prototype.getName = function() {
return this.name;
};
// 获取实例方法
Singleton.getInstance = (function(name) {
// 实例创建表示
var instance = null;
return function(name) {
if (!instance) {
instance = new Singleton(name);
}
return instance;
}
})();
说明:
我们通过 Singleton.getInstance
来获取 Singleton
类的唯一对象,这种方式相对简单,但有 一个问题,就是增加了这个类的“不透明性”,Singleton
类的使用者必须知道这是一个单例类, 跟以往通过 new XXX
的方式来获取对象不同,这里偏要使用 Singleton.getInstance
来获取对象。
虽然现在已经完成了一个单例模式的编写,但这段单例模式代码的意义并不大,我们会写出更好的单例。
2. 透明单例模式
我们现在的目标是实现一个“透明”的单例类,用户从这个类中创建对象的时候,可以像使 用其他任何普通类一样。
代码如下:
// 创建唯一Div的单例模式方法
var SingletonDiv = (function() {
var instance = null;
return function() {
if (!instance) {
instance = document.createElement('div');
instance = '<h1>Div</h1>';
}
return instance;
}
})();
var s1 = new SingletonDiv();
var s2 = new SingletonDiv();
console.info(s1 === s2); // true
说明:
虽然现在完成了一个透明的单例类的编写,但它同样有一些缺点。
为了把 instance
封装起来,我们使用了自执行的匿名函数和闭包,并且让这个匿名函数返回真正的 SingletonDiv
构造方法。
3. JS 通用单例
通过
getSingle
函数,可以灵活的产出各个组件的单例模式函数。
/**
* 获取单例函数
* @param {Function} fn 创建对象函数
* @return {Function} 单例函数
*/
function getSingle(fn) {
var result;
return function() {
return result || (result = fn.apply(this, arguments));
}
}
// 产出Div函数
var getDiv = function() {
var div = document.createElement('div');
div.innerHTML = '<h1>Div</h1>';
return div;
}
// 获取Div产出的单例模式函数
var getDivSingle = getSingle(getDiv);
var x1 = getDivSingle();
var x2 = getDivSingle();
console.info(x1 === x2); // true
var y1 = getDiv();
var y2 = getDiv();
console.info(y1 === y2); // false