单例模式的定义是: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏 览器中的 window 对象等。在 JavaScript 开发中,单例模式的用途同样非常广泛。试想一下,当我们单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。
实现
简单实现
/**
* 单例模式
*/
class Singleton {
constructor(name) {
this.name = name;
this.instance = null;
}
getName(){
console.log(this.name);
}
static getInstance(name){
if (!this.instance){
this.instance = new Singleton(name);
}
return this.instance;
};
}
const a = Singleton.getInstance('sven1');
const b = Singleton.getInstance('sven2');
console.log(a === b); // true
透明的单例模式
但是这个类需要实例化后调用方法才能创建实例,我们希望直接实例化时就能创建。
/**
* 使用闭包实现单例模式
*/
const Singleton = (function(){
let instance;
class SingletonOrigin {
constructor(name) {
if (instance) {
return instance;
}
this.name = name;
instance = this;
return this;
}
getName(){
console.log(this.name);
}
}
return SingletonOrigin;
})();
const a = new Singleton('sven1');
const b = new Singleton('sven2');
console.log(a === b); // true
为了把 instance 封装起来,我们使用了自执行的匿名函数和闭包,并且让这个匿名函数返回 真正的 Singleton 构造方法,这增加了一些程序的复杂度,阅读起来也不是很舒服。
使用代理实现单例模式
/**
* 使用代理实现单例模式
*/
const Singleton = (function (){
class SingletonOrigin {
constructor(name) {
this.name = name;
}
getName(){
console.log(this.name);
}
}
let instance;
return function(name) {
if (!instance){
instance = new SingletonOrigin(name);
}
return instance;
}
})();
const a = new Singleton('sven1');
const b = new Singleton('sven2');
console.log(a === b); // true
惰性单例模式
前面几种实现方式是基于面向对象思路的实现,现在使用js特殊的方式实现单例模式,名为惰性单例模式。
惰性单例模式可以推迟创建对象的时机,并不在一开始就创建,所以叫惰性。
/**
* 惰性单例模式
*/
const getInstance = (function () {
function createInstance(name) {
return {
name: name,
getName() {
console.log(this.name);
}
}
}
function getSingle (fn){
let result;
return function() {
if (!result) {
result = fn.apply(this, arguments)
}
return result;
}
};
return getSingle(createInstance);
})();
const a = getInstance('sven1');
const b = getInstance('sven2');
console.log(a === b); // true