Singleton(单例)模式限制了类的实例化次数只能一次,以前使用PHP的时候,常用单例模式来处理数据库连接,保证数据库句柄唯一。
Singleton模式,在实例不存在的情况下,可以通过一个方法创建一个类来实现创建类的新实例;如果实例已经存在,它会简单返回该对象的引用。
今天,采用JavaScript来实现单例模式。在JavaScript中,有多种方式可以实现单例模式。
1、使用对象字面值
代码如下:
var obj = {
name: 'wen'
};
在JavaScript中,对象之间永远不会完全相等,因此,可以认为在使用对象字面量创建对象的时候,就是创建一个单例。
2、重写构造函数
代码如下:
function Singleton() {
//缓存实例
var instance;
//重写构造函数
Singleton = function() {
return instance;
};
//保留原型
Singleton.prototype = this;
//实例
instance = new Singleton();
//构造函数指针
instance.constructor = Singleton;
return instance;
}
在这里,第一次实例化采用instance保存了Singleton的实例,通过重写构造函数保证了再次实例化时返回instance,保证了唯一性。
3、将构造函数和实例封装在闭包中
代码如下:
var Singleton;
(function() {
var instance;
Singleton = function() {
if (instance !== undefined) {
return instance;
}
instance = this;
};
}());
在第一次调用构造函数时,会创建一个对象,并且使得私有instance指向该对象,从第二次调用之后,该构造函数仅返回该私有变量。
当Singleton可以作为一个静态的实例实现时,它可以延时构建,直到需要使用静态实例之前,无需使用资源或内存。类似于PHP中getInstance返回一个实例,我们也采用getInstance来返回实例。代码如下:
var Singleton = (function () {
var _instance;
function init() {
/*单例代码*/
return {
user: 'Wen',
hi: function() {
console.log('My name is ' + this.user);
}
};
}
return {
getInstance: function () {
if (!_instance) {
_instance = init();
}
return _instance;
}
};
})();
采用如下方式调用:
Singleton.getInstance().hi();
接下来,实现一个单例通用化处理,将一个类转化成一个单例,并且采用自调用构造函数,使采用new方式或者非new方式调用保持一致,代码如下:
function singletonize(fn) {
//缓存实例
var instance;
//检查输入
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError('fn should be a function');
}
//单例
function Singleton() {
if (instance === undefined) {
var self = this instanceof Singleton ? this : Object.create(Singleton.prototype);
instance = self;
fn.apply(instance, arguments);//第一次初始化时调用原函数fn构造函数
}
return instance;
}
//继承
Singleton.prototype = fn.prototype;
return Singleton;
}
在通用化函数中,创建一个单例,在单例构造函数中,采用自调用,同时将参数传入fn构造函数中,并将单例的原型指向函数fn的原型,最终返回单例。采用如下方式调用:
function Test(user) {
this.username = user || 'wenwei';
}
var Test1 = singletonize(Test);
var test1 = Test1('wen'), test2 = new Test1();
console.log(test1 === test2); //true