JS單例模式《JavaScript設計模式與開發實踐》閱讀筆記

此文僅記錄本人閱讀《JavaScript設計模式與開發實踐》這個本時的感覺,感謝做者曾探寫出這麼好的一本書。若有冒犯,若有錯誤,請聯繫本人:luogao_lg@sina.com處理。javascript

這一章讓我知道了單例模式的核心就是:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。但在JavaScript中單例模式有別的區別於傳統面嚮對象語言的應用,惰性單例模式在實際的開發中有不少用途,例如提升頁面性能,避免沒必要要的DOM操做等。html

爲什麼要有單例模式

書中有舉出一個實際場景,當咱們點擊登錄按鈕時,頁面中可能會出現一個彈框,而這個彈框是惟一的,不管點多少次登錄按鈕,彈框只會被建立一次,那麼這種狀況下就適合用單例模式來建立彈框。java

實現一個簡單的單例模式

如下代碼來自書中編程

var CreateDiv = (function(html) {
    var instance
    var CreateDiv = function() {
        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.appendChild(div)
    }
    return CreateDiv
})()
複製代碼

以上代碼經過自執行函數和閉包將instance封裝起來。而且返回了真正的Singleton構造方法。設計模式

經過觀察上面代碼發現CreateDiv裏執行了兩個操做:閉包

  • 1.建立對象而且執行init方法。
  • 2.保證只有一個對象。這裏就暴露出一個問題。

若是某天咱們須要用這個方法向頁面中建立更多的元素。那咱們必需要改寫CreateDiv,若是咱們結合「單一職責原則」,咱們就知道要去把保證只有一個對象這個操做從CreateDiv抽離出來。這個目的能夠經過代理來實現。app

用代理實現單例模式

首先咱們把上面代碼中的CreateDiv方法改寫成一個只負責建立DIV的類函數

var CreateDiv = function(html) {
    this.html = html
    this.init()
}

CreateDiv.prototype.init = function() {
    var div = document.createElement('div')
    div.innerHTML = this.html
    document.appendChild(div)
}
複製代碼

接下來引入代理類性能

var ProxysingletonCreateDiv = (function() {
    var instance
    return function(html) {
        if (!instance) {
            instance = new CreateDiv(html)
        }
        return instance
    }
})()
var a = new ProxysingletonCreateDiv('test1')
var b = new ProxysingletonCreateDiv('test2')

alert(a === b) // true
複製代碼

至此利用代理類也實現了一個單例模式。但目前咱們討論的單例模式跟接近傳統面嚮對象語言中的實現。接下來咱們來了解一下JavaScript中的單例模式。網站

JavaScript中的單例模式——惰性單例

瞭解了單例模式的一些實現方法以後。咱們能夠來看看惰性單例的實現,這種實現方式在JavaScript的實際編程中是很實用的。

惰性單例

惰性單例是指在須要的時候才建立對象實例,而不是像以前的代碼那樣,利用自執行函數在代碼執行時就把對象實例建立。

好比最開始就提到,當打開一個網站時,須要登陸,但登錄的彈窗只會在點擊登錄按鈕時出現,甚至有的網站不須要登陸就能直接瀏覽。這時咱們並不須要在頁面加載時就去建立一個彈窗。咱們大可在須要用的時候去建立。

<html>
    <body>
        <button id="loginBtn">登陸</button>
    </body>
    <script> var createLoginLayer = (function() { var div return function() { if (!div) { var div = document.createElement('div') div.innerHTML = '我是登陸彈窗' div.style.display = 'none' document.appendChild(div) } return div } })() document.getElementById('loginBtn').onclick = function() { var loginLayer = createLoginLayer() loginLayer.style.display = 'block' } </script>
</html>
複製代碼

以上咱們實現了一個單例模式的彈窗。可是咱們仍是能夠把其中的控制只有一個對象的操做抽離出來,讓咱們來實現一個通用的惰性單例。

通用惰性單例

通用惰性單例的實現就是要抽離全部單例模式都要實現的——控制只有一個對象。那麼咱們來看看控制只有一個對象的操做抽象出來是個什麼樣子:

var obj 
if (!obj) {
    obj = xxx
}
複製代碼

因而就能夠把這個操做的邏輯封裝到一個getSingle函數中,而後把要執行的函數看成參數傳入進去:

var getSingle = function(fn) {
    var result
    return function() {
        result || (result = fn.apply(this, arguments))
    }
}
複製代碼

這樣咱們上面寫的建立彈窗的方法就能夠徹底抽離出來:

var createLoginLayer = function() {
    var div = document.createElement('div')
    div.innerHTML = '我是登陸彈窗'
    div.style.display = 'none'
    document.appendChild(div)
    return div
}

var createSingleLoginLayer = getsingle(createLoginLayer)

document.getElementById('loginBtn').onclick = function() {
    var loginLayer = createSingleLoginLayer()
    loginLayer.style.display = 'block'
}
複製代碼

至此咱們實現了一個getSingle函數來幫咱們實現只有一個實例對象的目的,而且將實例對象要作的指責獨立出來,兩個方法互不打擾。

最後

原文出自 Roy's Blog

參考

《JavaScript設計模式與開發實踐》—— 曾探

相關文章
相關標籤/搜索