單例模式是JS設計模式中一種經常使用的模式設計模式
保證一個類中僅有一個實例,且提供一個訪問它的全局訪問點閉包
一些只須要出現的一個UI組件,如登陸窗口、彈窗toast、遮罩maskapp
用一個變量來標記是否已建立過對象,若是是就返回已建立過對象,若是不是則建立對象函數
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,。優化
咱們要對上面的例子進行改造優化使得變得透明,和其餘獲取對象的方式同樣,使用new XXX的格式,下面大體實現了一下,例子中還有不少的不足,主要是提供使用new方式的一種思路。this
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
例子2雖然初步實現了咱們要的功能,可是在實際狀況中,建立一個對象的狀況可能複雜得多,例如傳參,給元素設定顏色,設定文字等,而createDiv函數就會變得臃腫,並且若是有一但願可能返回多個對象就須要對createDiv進行改造
能夠經過代理來實現,類負責具體的實現,單例決定要不要建立實例prototype
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
不過我的以爲爲了使用單例而去建立一個代理類有些浪費設計
上面三種方式都是去模仿傳統的面嚮對象語言去創造單例的,先定義類,再從類中去創造單例,但js自己是沒有類的,能夠不用定義類。從單例的定義來講,全局變量也是單例,可使用所有變量來建立單例,例如 var a={},但這種方式容易形成命名污染代理
惰性單例的意思是須要的時候才建立對象
惰性單例的實現能夠結合全局變量,由於前面說過既然是單例沒有必要去定義一個類。這個例子中把建立對象和管理單例分開,建立對象的函數做爲參數傳入管理單例函數中,實現不一樣單例的建立。這也是通用的惰性單例。code
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)
這裏的例子中雖然大有不一樣,可是都有一個共同點是利用了閉包的特性,延長判斷是否建立單例的變量的生命週期,對閉包有必定了瞭解更能體會到其中的妙處。