javascript單例模式的理解javascript
閱讀目錄html
理解單例模式java
單例模式的含義是: 保證一個類只有一個實例,並提供一個訪問它的全局訪問點。實現的方法是:使用一個變量來標誌當前是否已經爲某個類建立過對象,若是建立了,則在下一次獲取該類的實例時,直接返回以前建立的對象,不然就建立一個對象。這就確保了一個類只有一個實例對象。緩存
好比以下代碼是一個簡單的單例模式代碼實例:app
var Singleton = function(name){ this.name = name; // 使用instance 該標誌來判斷是否建立了一個實例 this.instance = null; }; Singleton.prototype.getName = function(){ console.log(this.name); }; Singleton.getInstance = function(name) { if(!this.instance) { this.instance = new Singleton(name); } return this.instance; }
如今咱們能夠來使用下,初始化下,以下代碼:dom
var a = Singleton.getInstance("aa"); var b = Singleton.getInstance("bbb"); console.log(a); console.log(b);
打印以下:函數
繼續以下測試:測試
console.log(a === b); // true a.getName(); // aa b.getName(); // aa a.test = "test"; console.log(b.test); // test
如上代碼測試,能夠看到,先是實例化一次,傳aa給name參數,保存到a變量中,第二次再次調用getIstance方法,因爲實例已經存在,因此使用以前第一次建立過的對象,所以 a ===b 爲true,a.getName()和b.getName()值打印都爲aa;this
咱們還能夠像以下方式來編寫代碼:spa
var Singleton = function(name){ this.name = name; }; Singleton.prototype.getName = function(){ console.log(this.name); }; Singleton.getInstance = (function(){ var instance = null; return function(name){ if(!instance) { instance = new Singleton(name); } return instance; } })();
使用代理實現單例模式
好比我如今想在頁面上建立一個div元素,以下使用代理實現單例模式的代碼:
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("aa"); var b = new ProxySingletonCreateDiv("bbb"); console.log(a === b); // true
如上代碼:咱們把負責管理單例的邏輯移到了ProxySingletonCreateDiv 函數中,CreateDiv函數就是一個普通的函數,就是隻是負責建立div的方法,那麼具體的管理單例的邏輯交給ProxySingletonCreateDiv函數;
理解惰性單例
惰性單例的含義是:在須要的時候才建立對象實例,而前面咱們講的是頁面加載完的時候就建立實例;好比咱們在頁面上一個彈出窗口的div,還有許多其餘的顯示元素,若是有些用戶不點擊那個彈窗的話,那麼在頁面初始化的時候多建立了一些dom節點,若是咱們使用惰性單例的話,咱們就能夠在用戶須要的時候纔去建立dom節點;
咱們首先來看看在頁面加載完成的時候去建立div彈窗。這個彈窗一開始是隱藏的,當用戶點擊某個按鈕的時候,這個彈窗才顯示;代碼以下:
<button id="btn">請點擊我</button>
var CreateDiv = (function(){ var div = document.createElement('div'); div.innerHTML = "我是彈窗測試"; div.style.display = "none"; document.body.appendChild(div); return div; })(); document.getElementById("btn").onclick = function(){ CreateDiv.style.display = "block"; }; 惰性代碼以下所示: var CreateDiv = function(){ var div = document.createElement('div'); div.innerHTML = "我是彈窗測試"; div.style.display = "none"; document.body.appendChild(div); return div; }; document.getElementById("btn").onclick = function(){ var createDiv = CreateDiv(); createDiv.style.display = "block"; };
如上代碼,咱們點擊按鈕的時候,纔去建立div元素,可是每次點擊的時候,咱們都得建立元素,這樣也不合理的。可是如上代碼,咱們可使用一個變量來判斷是否已經建立過div彈窗;以下所示:
var CreateDiv = (function(){ var div; return function(){ if(!div) { div = document.createElement('div'); div.innerHTML = "我是彈窗測試"; div.style.display = "none"; document.body.appendChild(div); } return div; } })(); document.getElementById("btn").onclick = function(){ var createDiv = CreateDiv(); createDiv.style.display = "block"; };
編寫通用的惰性單例
如上代碼雖然完成了惰性單例,可是有些問題;
好比若是我如今按照上面建立div的方法,如今咱們須要再建立一個iframe元素的話,代碼須要改爲以下:
var createIframe = (function(){ var iframe; return function(){ if(!iframe) { iframe = document.createElement('iframe'); iframe.style.display = 'none'; document.body.appendChild(iframe); } return iframe; } })();
咱們如今確定在考慮如何把上面的代碼公用出來,這樣就能夠實現抽象的代碼,管理單例的邏輯代碼其實能夠抽象出來,這個邏輯是同樣的,使用一個變量來標誌是否建立過對象,若是是,在下次直接返回這個已經建立好的對象;
咱們能夠把這些邏輯封裝在getSingle函數內部,建立對象的方法fn被當成參數動態傳入getSingle函數;以下代碼:
var getSingle = function(fn){ var result; return function(){ return result || (fn.apply(this,arguments)); }; };
下面咱們是使用getSingle建立一個div的方法以下:
var CreateDiv = function(){ var div = document.createElement('div'); div.innerHTML = "我是彈窗測試"; div.style.display = "none"; document.body.appendChild(div); return div; }; // 建立單例 var createSingleDiv = getSingle(CreateDiv); document.getElementById("btn").onclick = function(){ // 調用單例方法 var createDiv = createSingleDiv(); createDiv.style.display = "block"; };
好比如今咱們須要建立一個iframe,那麼代碼以下:
var createSingleIframe = getSingle(function(){ var iframe = document.createElement('iframe'); document.body.appendChild(iframe); return iframe; }); document.getElementById("btn").onclick = function(){ // 調用單例方法 var createSingleIframe = createSingleIframe(); createSingleIframe.src = "http://cnblogs.com"; };
單例模式使用場景
有一些對象咱們只須要一個的狀況下,好比彈窗這樣的,全局緩存,遊覽器window對象等。
單例模式只會建立一個實例,且僅有一個實例,好比咱們一剛開始講到的,
var a = Singleton.getInstance("aa"); var b = Singleton.getInstance("bbb"); console.log(a === b); // true a.getName(); // aa b.getName(); // aa
咱們明明第一次傳的是aa,第二次傳的參數是bbb,爲何都調用getName()方法後都打印出aa呢,這就是單例模式只建立一個實例的地方;