JS設計模式——單例模式剖析

轉載於原文地址:https://blog.csdn.net/q1056843325/article/details/52933426緩存

舉一個通俗的例子,在頁面中點擊登陸按鈕,彈出了一個登陸浮窗,這個登陸浮窗是惟一的,不管咱們單擊多少次,浮窗只會建立一次。閉包

其實咱們可能無心中都會使用過單例模式,咱們的作法每每都是使用一個變量來標誌當前是否已經爲某個類建立了對象, 若是true,那麼下一次再想得到這個類的實例時,直接返回以前建立過的對象。app

單例模式的核心是確保只有一個實例,並提供全局訪問。函數

 

其實在JavaScript中,單例模式並無這麼複雜 
this

var a = {};

咱們這樣建立了對象a,它確實獨一無二 
並且知足了單例模式的兩個條件spa

  • 一個實例
  • 全局訪問

可是全局變量很容易形成命名空間污染 ,若是項目很大的話,不當心覆蓋了變量那就是致命的。.net

因此,在詳細講解這個單例模式以前,咱們先來討論這樣一個問題,怎樣下降全局污染? (全局污染也就是變量大量存在於全局做用域污染了全局空間 )code

下降全局污染有兩種辦法:對象

一、使用命名空間

var namespace_payen = {
    a: function(){
        //...
    }
    b: function(){
        //...
    }
}

適當使用命名空間,並不會杜絕全局變量,可是能夠減小全局變量的數量blog

二、使用閉包封裝私有變量

var payen = (function(){
    var _name = 'payson.Tsung',
        _age = 19;
    return {
        getInfo: function(){
            return _name + ' ' + _age;
        }
    }
})();

變量被封裝在了閉包內,只暴露一些接口用於外部通訊,從而避免了對全局的命令污染

 

下面我來談談這個單例模式 

先來個簡單的例子 

下面我聲明瞭一個函數,每次調用都建立一個小方塊

function createDiv(){
    var div = document.createElement('div');
    div.style.width = '100px';
    div.style.height = '100px';
    div.style.background = 'red';
    div.style.marginBottom = '10px';
    document.body.appendChild(div);
}
createDiv();
createDiv();
createDiv();

調用了三次,頁面出現了三個小方塊 

 

下面我就使用單例模式,讓它只建立一個div 

var createDiv = (function(){
    var div;
    return function(){
        if(!div){
            div = document.createElement('div');
            div.style.width = '100px';
            div.style.height = '100px';
            div.style.background = 'red';
            div.style.marginBottom = '10px';
            document.body.appendChild(div);
        }
    }
})();
createDiv();
createDiv();
createDiv();

 再來看看頁面,只有一個小方塊 

 

div聲明在當即執行函數中做爲私有變量 ,沒有執行函數前, div值爲undefined ,第一次執行函數時,判斷div,若是沒有,建立了一個DOM節點而且插入到了文檔; 隨後再執行函數時,div變量已經緩存了剛剛建立的DOM節點,再也不建立 ,不管執行幾回,小方塊只會建立一次 ,這就是單例模式,並且是一個惰性單例。

惰性單例就是在須要的時候才建立對象實例,而非在頁面加載時就建立 ,這樣作的好處你們都知道。

 

雖然咱們完成了惰性單例,可是咱們一樣發現了問題

  • 違反了單一職責原則,建立對象和管理單例放在了一個函數中createDiv
  • 若是咱們還想建立一個其餘的惟一對象,那就只能copy了

綜上,咱們須要把不變的部分隔離出來,把可變的封裝起來,這給予了咱們擴展程序的能力,符合「開放-封閉原則」;

下面咱們就抽出管理單例的邏輯 ,不管怎樣抽取,萬變不離其中,用一個變量來標誌是否建立過對象

var getSingle = function(fn){
    var result;
    return function(){
        return result || (result = fn.apply(this, arguments));
    }
};
var createDiv = function(){
    var div = document.createElement('div');
    div.style.width = '100px';
    div.style.height = '100px';
    div.style.background = 'red';
    div.style.marginBottom = '10px';
    document.body.appendChild(div);
    return div;
};
var createSingleDiv = getSingle(createDiv);
createSingleDiv();
createSingleDiv();
createSingleDiv();

建立的DOM節點保存在了result中 ,result變量由於自身在閉包中,不會被銷燬,若是result已經被賦值了,那麼它將返回這個值 ;

單例模式很簡單,並且也十分實用,他不只僅用於建立對象,還有不少其餘用途 ,好比說只綁定一次事件啦之類的

相關文章
相關標籤/搜索