成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用最簡單的方式聊一下JavaScript中的觀察者模式

megatron / 3183人閱讀

摘要:觀察者模式,是設(shè)計模式之一。即便如此,筆者仍精心準(zhǔn)備了這篇博客,期望用最簡單的方式來介紹下該模式。這里有個小知識點提一下函數(shù)對象的屬性就是該函數(shù)名最后是思路是通過找到指定數(shù)組,然后對數(shù)組中的回調(diào)函數(shù)進(jìn)行依次調(diào)用,達(dá)到發(fā)布的目的。

觀察者模式,是JavaScript設(shè)計模式之一。當(dāng)然也不僅僅限于JavaScript這門語言,網(wǎng)上對該模式的介紹已是多如牛毛,而且講得各有特色各有心得。即便如此,筆者仍精心準(zhǔn)備了這篇博客,期望用最簡單的方式來介紹下該模式。

首先來看下維基百科對 觀察者模式 的解釋:

觀察者模式是軟件設(shè)計模式的一種。在此種模式中,一個目標(biāo)對象管理所有相依于它的觀察者對象,并且在它本身的狀態(tài)改變時主動發(fā)出通知。這通常透過呼叫各觀察者所提供的方法來實現(xiàn)。此種模式通常被用來實時事件處理系統(tǒng)。

其實筆者更傾向于它的另一個名字發(fā)布/訂閱模式(Publish/Subscribe),因為更能表達(dá)出該模式的核心思路,那就是:發(fā)布訂閱兩個過程。是不是還感覺模棱兩可?不用擔(dān)心,下面就用咱們身邊發(fā)生的事情來做個形象化的解釋:
大家都有訂閱網(wǎng)站郵件的經(jīng)歷吧?如果你沒有的話,emmmmm....那就繼續(xù)往下看吧哈哈!!
假如我今天想訂閱xxx公司的郵件,那么這里就涉及到兩個對象:xxx公司,
從行為上來看就是我訂閱了xxx公司郵件,xxx公司會發(fā)送郵件給我的郵箱。但某天我不想再收到xxx公司的郵件了,那么我可以取消訂閱,這樣xxx公司就不會再發(fā)郵件到我的郵箱。

說到這里,是不是就有點眉頭了呢?好,我們繼續(xù)往下說,
通過剛剛的形象化解釋,我們可以羅列下觀察者模式的一些核心的東西:

對象:我(訂閱者), xxx公司(發(fā)布者), 可以直接對應(yīng) 發(fā)布/訂閱模式(Publish/Subscribe)
行為:訂閱發(fā)送取消訂閱

說不如做,下面開始用代碼來更直觀的描繪下觀察者模式吧。
首先我們定義一個發(fā)布者 (相當(dāng)于xxx公司)

let publisher = {
    
}

那么一起來按照訂閱郵件的過程想象下,發(fā)布者具有那些屬性或者方法?

首先,我們訂閱一個xxx網(wǎng)站的郵件,是不是需要xxx網(wǎng)站給我們提供訂閱入口?那么publisher中必定會有一個方法提供給我們實現(xiàn)訂閱

其次,如果xxx公司要向訂閱者們發(fā)送自己的郵件,是不是需要一個方法去做?那么publisher中必定會有一個方法提供給我們實現(xiàn)發(fā)送或者說說發(fā)布。

再然后,如例子所說如果我突然不想訂閱xxx公司的郵件了,xxx公司 就得提供給我一個取消訂閱的入口,那么publisher中必定會有一個方法提供給我們實現(xiàn)取消訂閱。

最后,如果我們訂閱了xxx公司的郵件,那么他就得記錄我訂閱所用的郵箱地址吧,所以publisher中必定會有一個“注冊表”來存儲訂閱的對象,也就是說我們的 郵箱地址。

說到這里一切都了然了,下面還是講想象到的東西用代碼表達(dá)出來吧

let publisher = {
    registration: {},
    subscribe: function (type, fn) {},
    unSubscribe: function (type, fnName) {},
    publish: function (type, message) {}
}

簡單解釋下,

registration就是上面提到的注冊表,至于為什么把它設(shè)計成一個對象是因為考慮到xxx公司可能有更多類型的郵件,比如 游戲,金融,投資理財?shù)鹊?,所以就把它設(shè)計成對象以key-value的形式存儲訂閱者, 比如:{"game":[],"monetary":[]}該形式

subscribe 則是publisher提供給我們的對其進(jìn)行訂閱的方法,參數(shù)是typefn。type就是郵件的類型,fn就是我們提供給publisher用于通知我的渠道 (郵箱)。在JavaScript中更多的是回調(diào)函數(shù)。

unSubscribepublisher提供給我們的對其進(jìn)行取消訂閱的方法,參數(shù)是typefnName。type就不多說了,fnName則是我們提供給publisher用于取消訂閱的標(biāo)志,比如說郵箱,或者是回調(diào)函數(shù)的名字等等。

publish說到比較重要的方法,這就是publisher向所有訂閱者發(fā)布消息的方法。

下面開始一步一步得實現(xiàn)三個方法,registration保持不變:

首先是subscribe
subscribe: function (type, fn) {
    if (Object.keys(this.registration).indexOf(type) >= 0) {
        this.registration[type].push(fn);
    } else {
        this.registration[type] = [];
        this.registration[type].push(fn);
    }
}

這里的思路是將 Callback Function 存儲到registration對于類型的數(shù)組中,以待publish調(diào)用。

然后是 unSubscribe
unSubscribe: function (type, fnName) {
    if (Object.keys(this.registration).indexOf(type) >= 0) {
        let index = -1;
        this.registration[type].forEach(function (func, idx) {
            if (func.name === fnName) {
                index = idx;
            }
        })
        index > -1 ? this.registration[type].splice(index, 1) : null
    }
}

思路是首先通過 type 確定數(shù)組對象,然后通過方法對象的名字進(jìn)行判斷,最后直接剔除操作。
** 這里有個小知識點提一下:函數(shù)對象的name屬性就是該函數(shù)名 **

最后是 publish
publish: function (type, message) {
    if (Object.keys(this.registration).indexOf(type) >= 0) {
        for (let fn of this.registration[type]) {
            fn(message)
        }
    }
}

思路是通過 type 找到指定數(shù)組,然后對數(shù)組中的回調(diào)函數(shù)進(jìn)行依次調(diào)用,達(dá)到發(fā)布的目的。

寫到這里,發(fā)布者Publisher已經(jīng)完成。那么下面開始寫訂閱者Subscriber,如上面所說其實訂閱者就是一個 回調(diào)函數(shù),例如:

let subscriber = function (param) {
    //do something
}

所以下面將整個代碼展示并演示下效果:

let publisher = {
    registration: {},
    subscribe: function (type, fn) {
        if (Object.keys(this.registration).indexOf(type) >= 0) {
            this.registration[type].push(fn);
        } else {
            this.registration[type] = [];
            this.registration[type].push(fn);
        }
    },
    unSubscribe: function (type, fnName) {
        if (Object.keys(this.registration).indexOf(type) >= 0) {
            let index = -1;
            this.registration[type].forEach(function (func, idx) {
                if (func.name === fnName) {
                    index = idx;
                }
            })
            index > -1 ? this.registration[type].splice(index, 1) : null
        }
    },
    publish: function (type, message) {
        if (Object.keys(this.registration).indexOf(type) >= 0) {
            for (let fn of this.registration[type]) {
                fn(message)
            }
        }
    }
}

let subscriberA = function (message) {
    console.log(`A收到通知:${message}`)
};

let subscriberB = function (message) {
    console.log(`B收到通知:${message}`)
};

let subscriberC = function (message) {
    console.log(`C收到通知:${message}`)
};

publisher.subscribe("game", subscriberA);
publisher.subscribe("game", subscriberB);
publisher.subscribe("game", subscriberC);

publisher.publish("game", "恭喜RNG獲得LOL 2018季中賽冠軍!")

運行看下結(jié)果:

結(jié)果如想象中一樣。
那再試一下取消訂閱,在 publish 之前加一段

publisher.unSubscribe("game", subscriberB.name)

再運行看下結(jié)果:

我們已經(jīng)看到 訂閱者B 在取消訂閱后就沒再收到任何消息。

其實觀察者模式能做的東西還有很多,比如事件的監(jiān)聽、狀態(tài)發(fā)生變化時的廣播等等。已經(jīng)有過接觸的朋友都可能意識到這個模式特別靈活,在兩個角色之間正常通信的同時也盡可能得實現(xiàn)了解耦,給開發(fā)帶來極大的便利。其中有名的 Knockout 的核心之一就是觀察者模式,所以說觀察者模式在前端開發(fā)中起到了舉足輕重的作用。

源碼在這,有興趣的朋友可以看下

好了,寫到這里本篇博客就結(jié)束了。有問題的朋友可以在下方討論;如果文章有不足或者錯誤的地方,煩請大家多多指正。Thanks !!!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/95743.html

相關(guān)文章

  • 聽飛狐JavaScript設(shè)計模式系列03

    摘要:閉包與柯里化閉包有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)??吕锘呀邮芏鄠€參數(shù)的函數(shù)變換成接受一個單一參數(shù)最初函數(shù)的第一個參數(shù)的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。 本回內(nèi)容介紹 上一回聊到JS的Object類型,簡單模擬了一下Java的Map,介一講,偶們來聊一下函數(shù)好唔好,介可系JS世界的一等公民喲。從函數(shù)開始,我們就將逐步過渡到設(shè)計模式,來吧,帥狐帶你裝逼帶你飛:...

    levy9527 評論0 收藏0
  • 聽飛狐JavaScript設(shè)計模式系列04

    摘要:介一回,偶們來聊一下用中的類,有些盆友可能用過或者的,知道語法糖,可是在中并沒有,中需要用到構(gòu)造函數(shù)來模擬類。而且要注意一點,構(gòu)造函數(shù)沒有語句,是自動返回。 本回內(nèi)容介紹 上一回聊到JS的Function類型,做了柯里化,數(shù)組去重,排序的題。 介一回,偶們來聊一下用JS中的類,有些盆友可能用過ES6或者TypeScript的,知道Class語法糖,可是在ES5中并沒有,ES5中需要用到...

    kgbook 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。插....

    izhuhaodev 評論0 收藏0
  • 聽飛狐JavaScript設(shè)計模式系列08

    摘要:本回內(nèi)容介紹上一回聊到工廠模式,略抽象。官方說法,門面模式是指提供一個統(tǒng)一的接口去訪問多個子系統(tǒng)的多個不同的接口,為子系統(tǒng)中的一組接口提供一個統(tǒng)一的高層接口。使得子系統(tǒng)更容易使用。 本回內(nèi)容介紹 上一回聊到工廠模式,略抽象。介一回,咱聊門面模式就比較容易了,門面模式也叫外觀模式(facade)。官方說法,門面模式是指提供一個統(tǒng)一的接口去訪問多個子系統(tǒng)的多個不同的接口,為子系統(tǒng)中的一組接...

    saucxs 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<