js 單例模式

為何要有單例模式
書中有舉出一個(gè)實(shí)際場(chǎng)景,當(dāng)我們點(diǎn)擊登陸按鈕時(shí),頁面中可能會(huì)出現(xiàn)一個(gè)彈框,而這個(gè)彈框是唯一的,無論點(diǎn)多少次登陸按鈕,彈框只會(huì)被創(chuàng)建一次,那么這種情況下就適合用單例模式來創(chuàng)建彈框。
實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單例模式
以下代碼來自書中

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
})()

以上代碼通過自執(zhí)行函數(shù)和閉包將instance封裝起來。并且返回了真正的Singleton構(gòu)造方法。

通過觀察上面代碼發(fā)現(xiàn)CreateDiv里執(zhí)行了兩個(gè)操作:

1.創(chuàng)建對(duì)象并且執(zhí)行init方法。
2.保證只有一個(gè)對(duì)象。這里就暴露出一個(gè)問題。

如果某天我們需要用這個(gè)方法向頁面中創(chuàng)建更多的元素。那我們必須要改寫CreateDiv,如果我們結(jié)合“單一職責(zé)原則”,我們就知道要去把保證只有一個(gè)對(duì)象這個(gè)操作從CreateDiv抽離出來。這個(gè)目的可以通過代理來實(shí)現(xiàn)。
用代理實(shí)現(xiàn)單例模式
首先我們把上面代碼中的CreateDiv方法改寫成一個(gè)只負(fù)責(zé)創(chuàng)建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

至此利用代理類也實(shí)現(xiàn)了一個(gè)單例模式。但目前我們討論的單例模式跟接近傳統(tǒng)面向?qū)ο笳Z言中的實(shí)現(xiàn)。接下來我們來了解一下JavaScript中的單例模式。
JavaScript中的單例模式——惰性單例
了解了單例模式的一些實(shí)現(xiàn)方法之后。我們可以來看看惰性單例的實(shí)現(xiàn),這種實(shí)現(xiàn)方式在JavaScript的實(shí)際編程中是很實(shí)用的。
惰性單例
惰性單例是指在需要的時(shí)候才創(chuàng)建對(duì)象實(shí)例,而不是像之前的代碼那樣,利用自執(zhí)行函數(shù)在代碼執(zhí)行時(shí)就把對(duì)象實(shí)例創(chuàng)建。
比如最開始就提到,當(dāng)打開一個(gè)網(wǎng)站時(shí),需要登錄,但登陸的彈窗只會(huì)在點(diǎn)擊登陸按鈕時(shí)出現(xiàn),甚至有的網(wǎng)站不需要登錄就能直接瀏覽。這時(shí)我們并不需要在頁面加載時(shí)就去創(chuàng)建一個(gè)彈窗。我們大可在需要用的時(shí)候去創(chuàng)建。

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

以上我們實(shí)現(xiàn)了一個(gè)單例模式的彈窗。但是我們還是可以把其中的控制只有一個(gè)對(duì)象的操作抽離出來,讓我們來實(shí)現(xiàn)一個(gè)通用的惰性單例。
通用惰性單例
通用惰性單例的實(shí)現(xiàn)就是要抽離所有單例模式都要實(shí)現(xiàn)的——控制只有一個(gè)對(duì)象。那么我們來看看控制只有一個(gè)對(duì)象的操作抽象出來是個(gè)什么樣子:

var obj 
if (!obj) {
    obj = xxx
}

于是就可以把這個(gè)操作的邏輯封裝到一個(gè)getSingle函數(shù)中,然后把要執(zhí)行的函數(shù)當(dāng)作參數(shù)傳入進(jìn)去:

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

這樣我們上面寫的創(chuàng)建彈窗的方法就可以完全抽離出來:

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

至此我們實(shí)現(xiàn)了一個(gè)getSingle函數(shù)來幫我們實(shí)現(xiàn)只有一個(gè)實(shí)例對(duì)象的目的,并且將實(shí)例對(duì)象要做的指責(zé)獨(dú)立出來,兩個(gè)方法互不打擾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 8,110評(píng)論 2 17
  • 單例模式 適用場(chǎng)景:可能會(huì)在場(chǎng)景中使用到對(duì)象,但只有一個(gè)實(shí)例,加載時(shí)并不主動(dòng)創(chuàng)建,需要時(shí)才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,311評(píng)論 1 10
  • 前端開發(fā)工程師必備系列-幾個(gè)簡(jiǎn)單的JS單例模式 JavaScript單例模式 1. 單例模式 單例模式(Singl...
    WEB開發(fā)李家靖閱讀 626評(píng)論 1 0
  • 1. 常見實(shí)現(xiàn)單例 要實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn)的單例模式并不復(fù)雜,無非是用一個(gè)變量來標(biāo)志當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建過對(duì)象,如果是...
    rocneal閱讀 1,341評(píng)論 0 0
  • 單例模式 單例表示只存在一個(gè)這樣的對(duì)象。單例模式是一種非常重要的設(shè)計(jì)模式,有很多經(jīng)典的應(yīng)用場(chǎng)景,比如說,網(wǎng)站的登錄...
    bigtom閱讀 319評(píng)論 0 0

友情鏈接更多精彩內(nèi)容