1. 介绍
单例模式是JS设计模式中一种常用的模式
2. 定义
保证一个类中仅有一个实例,且提供一个访问它的全局访问点
3. 应用
一些只需要出现的一个UI组件,如登录窗口、弹窗toast、遮罩mask
4. 思想
用一个变量来标记是否已创建过对象,如果是就返回已创建过对象,如果不是则创建对象
5. 实现
1.基本的单例模式
var Singleton=function(){
this.instance=null
}
Singleton.getInstance=(function(){
var instance=null
return function(){
if(!instance){
instance=new Singleton()
}
return instance
}
})()
Singleton.getInstance()
这就是一个基本的单例模式,但是这个单例模式看起来有些怪异,要求使用者必须知道Singleton类是一个单例类,不透明。获取对象一般是new XXX实现而这里是需要调用Singlenton的静态函数getInstance,。
2. 透明单例模式
我们要对上面的例子进行改造优化使得变得透明,和其他获取对象的方式一样,使用new XXX的格式,下面大致实现了一下,例子中还有很多的不足,主要是提供使用new方式的一种思路。
var Singleton=(function(){
var instance=null
var createDiv=function(){
if(instance){
return instance
}
instance=document.createElement("div")
instance.innerHTML="div"
}
return function(){
return instance||(instance=createDiv.apply(this))
}
})()
var a = new Singleton()
var b=new Singleton()
console.log(a===b)//true
3. 用代理实现单例模式
例子2虽然初步实现了我们要的功能,但是在实际情况中,创建一个对象的情况可能复杂得多,例如传参,给元素设定颜色,设定文字等,而createDiv函数就会变得臃肿,而且如果有一希望可能返回多个对象就需要对createDiv进行改造
可以通过代理来实现,类负责具体的实现,单例决定要不要创建实例
var Singleton=function(){
this.createDiv()
}
Singleton.prototype.createDiv=function(){
this.instance= document.createElement("div")
}
var ProxySinglenton=(function(){
var instance
return function(){
if(!instance){
instance=new Singleton()
}
return instance
}
})()
var a = new ProxySinglenton()
var b = new ProxySinglenton()
console.log(a===b)//true
不过个人觉得为了使用单例而去创建一个代理类有些浪费
4. 使用全局变量
上面三种方式都是去模仿传统的面向对象语言去创造单例的,先定义类,再从类中去创造单例,但js本身是没有类的,可以不用定义类。从单例的定义来说,全局变量也是单例,可以使用全部变量来创建单例,例如 var a={},但这种方式容易造成命名污染
5. 惰性单例
惰性单例的意思是需要的时候才创建对象
惰性单例的实现可以结合全局变量,因为前面说过既然是单例没有必要去定义一个类。这个例子中把创建对象和管理单例分开,创建对象的函数作为参数传入管理单例函数中,实现不同单例的创建。这也是通用的惰性单例。
var getSingle=function(fn){
var result
return function(){
return result||(result=fn.apply(this))
}
}
var createSingleDiv=function(){
var div=document.createElement("div")
return div
}
var createP=function(){
var p =document.createElement("p")
return p
}
var createSingleDiv=getSingle(createDiv)
var createSingleP=getSingle(createP)
6. 建议
这里的例子中虽然大有不同,但是都有一个共同点是利用了闭包的特性,延长判断是否创建单例的变量的生命周期,对闭包有一定了了解更能体会到其中的妙处。