单例模式
单例模式,顾名思义,只有一个实例。那么问题来了,什么只有一个实例。在 js 里面,能够创建实例的有构造函数和类(es6 新增,本质上是语法糖)。
所以单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
在前端开发中,对于一些全局对象往往只需要一个,比如 window 对象。还有一些组件也不需要重复创建,比如 loading 组件。
实现单例模式
知道了单例模式是什么,实现一个单例模式也就并不困难。使用一个变量缓存实例就可以,每次创建实例判断是否已经创建过实例,如果是,返回缓存实例,
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 a = Singleton.getInstance('instance1');
var b = Singleton.getInstance('instance2');
console.log(a === b); // true
还可以使用 IIFE 实现,将实例缓存在闭包里面:
var Singleton = function(name) {
this.name = name;
};
Singleton.prototype.getName = function() {
return this.name;
};
Singleton.getInstance = function() {
var instance = null;
return function(name) {
if (!instance) {
instance = new Singleton(name);
}
return instance;
};
};
var a = Singleton.getInstance('instance1');
var b = Singleton.getInstance('instance2');
console.log(a === b); // true
现在可以通过 Singleton.getInstance 来获取 Singleton 类的唯一实例。这种方式比较简单。与以往 new 的语法不符,需要使用者必须知道这是一个单例类。
创建一个透明的单例类:
var Singleton = (function() {
var instance = null;
var Singleton = function(name) {
if (instance) {
return instance;
}
this.name = name;
return (instance = this);
};
return Singleton;
})();
用闭包和立即执行函数实现了一个用 new 来获取唯一实例的单例类。
但是有一个问题,这个类实际上做了两件事,创建对象和保证单例,当我们想要修改其中一个行为的时候就必须修改这个对象,这个时候我们可以引入代理类。
引入代理类
代理类保证单例,创建对象由专门对象负责。
var Singleton = function(name) {
this.name = name;
};
var ProxySingleton = (function() {
var instance = null;
return function(name) {
if (!instance) {
instance = new Singleton(name);
}
return instance;
};
})();
var a = new ProxySingleton('instance1');
var b = new ProxySingleton('instance2');
console.log(a === b); // true
惰性单例
惰性单例是指在需要的时候才创建对象实例。事实上我们开头写的实现就是一个惰性单例实例。instance 实例对象总是在调用 Singleton.getInstance 后创建。
小结
由示例可以看出,单例模式的实现离不开闭包和高阶函数,并且单例模式最好将保证单例和创建对象分开,这样才能具有单例模式的威力。
PS
这是我的读书笔记,如有错漏之处,欢迎各位大佬指出。