javascript單例模式的理解

來源:互聯網
上載者:User

標籤:

javascript單例模式的理解

閱讀目錄

  • 理解單例模式
  • 使用代理實現單例模式
  • 理解惰性單例
  • 編寫通用的惰性單例
  • 單例模式使用情境
回到頂部

理解單例模式

單例模式的含義是: 保證一個類只有一個執行個體,並提供一個訪問它的全域訪問點。實現的方法是:使用一個變數來標誌當前是否已經為某個類建立過對象,如果建立了,則在下一次擷取該類的執行個體時,直接返回之前建立的對象,否則就建立一個對象。這就確保了一個類只有一個執行個體對象。

比如如下代碼是一個簡單的單例模式代碼執行個體:

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;}

現在我們可以來使用下,初始化下,如下代碼:

var a = Singleton.getInstance("aa");var b = Singleton.getInstance("bbb");console.log(a);console.log(b);

列印如下:

繼續如下測試:

console.log(a === b);  // truea.getName();  // aab.getName();  // aaa.test = "test";console.log(b.test); // test

如上代碼測試,可以看到,先是執行個體化一次,傳aa給name參數,儲存到a變數中,第二次再次調用getIstance方法,由於執行個體已經存在,所以使用之前第一次建立過的對象,因此 a ===b 為true,a.getName()和b.getName()值列印都為aa;

我們還可以像如下方式來編寫代碼:

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";    };
回到頂部

編寫通用的惰性單例

如上代碼雖然完成了惰性單例,但是有些問題;

  1. 違反了單一職責原則;比如建立對象和管理單例的邏輯都放在CreateDiv對象內部;
  2. 沒有把代碼抽象出來,比如上面的是建立一個div元素,但是以後我想建立一個script元素或者一個iframe元素的話,那麼我們還需要複製上面的代碼重寫下;

比如如果我現在按照上面建立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);  // truea.getName();  // aab.getName();  // aa

我們明明第一次傳的是aa,第二次傳的參數是bbb,為什麼都調用getName()方法後都列印出aa呢,這就是單例模式只建立一個執行個體的地方;

javascript單例模式的理解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.