傳統單例模式html
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。編程
實現單例核心思想閉包
無非是用一個變量來標誌當前是否已經爲某個類建立過對象,若是是,則在下一次獲取該類的實例時,直接返回以前建立的對象,接下來咱們用JavaScript來強行實現這個思路,請看代碼:app
var Singleton = function( name ){ this.name = name; };
Singleton.prototype.getName = function(){
alert ( this.name ); };
Singleton.getInstance = (function(){
var instance = null;
return function( name ){ if ( !instance ){ instance = new Singleton( name ); } return instance;
} })();
咱們經過Singleton.getInstance來獲取Singleton類的惟一對象,這樣確實是沒問題的,可是js自己是沒有類這種概念的,因此咱們強行用傳統單例思想來實現是沒有任何意義的,這樣的代碼又臭又長(實際上是我本身看着不舒服嘻嘻嘻)。下面咱們使用JavaScript的閉包來實現一個單例,請看代碼:函數
var CreateDiv = (function(){
var instance; var CreateDiv = function( html ){
if ( instance ){ return instance;
} this.html = html; this.init(); return instance = this; }; CreateDiv.prototype.init = function(){ var div = document.createElement( 'div' );
div.innerHTML = this.html;
document.body.appendChild( div ); }; return CreateDiv;
})();
var a = new CreateDiv( 'sven1' );
var b = new CreateDiv( 'sven2' ); alert ( a === b ); // true
能夠看到,這樣咱們確實用閉包來實現了一個單例,但這個代碼仍是高度耦合的,CreateDiv的構造函數實際上負責了兩件事情。第一是建立對象和執行初始化init方法,第二是保證只有一個對象。這樣的代碼是職責不明確的,如今咱們要把這兩個工做分開,構造函數就負責構建對象,至於判斷是返回現有對象仍是構造新的對象並返回,咱們交給另一個函數去完成,其實也就是爲了知足一個編程思想:單一職責原則。這樣的代碼才能更好的解耦,請看下面代碼:性能
var CreateDiv = function (html) { this.html = html; this.init(); }; CreateDiv.prototype.init = function () { var div = document.createElement('div'); div.innerHTML = this.html; document.body.appendChild(div); }; var ProxySingletonCreateDiv = (function () { var instance; return function (html) { if (!instance) { instance = new CreateDiv(html); } return instance; } })(); var a = new ProxySingletonCreateDiv('sven1'); var b = new ProxySingletonCreateDiv('sven2'); alert(a === b); //true
能夠看到,如今咱們的構造函數CreateDiv如今只負責構造對象,至因而返回現有對象仍是構造新的對象並返回,這件事咱們交給了代理類proxySingletonCreateDiv來處理,這樣的代碼看着才舒(zhuang)服(bi)嘛!this
最後貼一個高度抽象的單例模式代碼,惰性單例的精髓!!:spa
//單例模式抽象,分離建立對象的函數和判斷對象是否已經建立 var getSingle = function (fn) { var result; return function () { return result || ( result = fn.apply(this, arguments) ); } };
形參fn是咱們的構造函數,咱們只要傳入任何本身須要的構造函數,就能生成一個新的惰性單例。好比說傳入建立一個女友的構造函數,而且調用getSingle(),就能生成一個新的女友。若是之後再調getSingle(),也只會返回剛纔建立的那個女友。至於新女友——不存在的。prototype
單例經常使用場景代理
只須要生成一個惟一對象的時候,好比說頁面登陸框,只可能有一個登陸框,那麼你就能夠用單例的思想去實現他,固然你不用單例的思想實現也行,那帶來的結果可能就是你每次要顯示登錄框的時候都要從新生成一個登錄框並顯示(耗費性能),或者是不當心顯示出了兩個登陸框(等着吃經理的40米長刀吧),嘻嘻嘻。