【轉(zhuǎn)】JavaScript的觀察者模式(Vue雙向綁定原理)

關(guān)于Vue實(shí)現(xiàn)數(shù)據(jù)雙向綁定的原理,請(qǐng)點(diǎn)擊:Vue實(shí)現(xiàn)數(shù)據(jù)雙向綁定的原理
原文鏈接:JavaScript設(shè)計(jì)模式之觀察者模式

什么是觀察者模式?

觀察者模式(Observer)通常又被稱為 發(fā)布-訂閱者模式消息機(jī)制,它定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,只要當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新,解決了主體對(duì)象與觀察者之間功能的耦合,即一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問(wèn)題。

比如比較當(dāng)下熱門 vue 框架,里面不少地方都涉及到了觀察者模式,比如:

數(shù)據(jù)的雙向綁定.png

利用Object.defineProperty()對(duì)數(shù)據(jù)進(jìn)行劫持,設(shè)置一個(gè)監(jiān)聽(tīng)器 Observer,用來(lái)監(jiān)聽(tīng)所有屬性,如果屬性上發(fā)上變化了,就需要告訴訂閱者 Watcher去更新數(shù)據(jù),最后指令解析器 Compile解析對(duì)應(yīng)的指令,進(jìn)而會(huì)執(zhí)行對(duì)應(yīng)的更新函數(shù),從而更新視圖,實(shí)現(xiàn)了雙向綁定~

創(chuàng)建一個(gè)觀察者

首先我們需要?jiǎng)?chuàng)建一個(gè)觀察者對(duì)象,它包含一個(gè)消息容器和三個(gè)方法,分別是訂閱消息方法on , 取消訂閱消息方法 off ,發(fā)送訂閱消息 subscribe 。

    const Observe = (function () {
        //防止消息隊(duì)列暴露而被篡改,將消息容器設(shè)置為私有變量
        let __message = {};
        return {
            //注冊(cè)消息接口
            on : function () {},
            //發(fā)布消息接口
            subscribe : function () {},
            //移除消息接口
            off : function () {}
        }
    })();

注冊(cè)消息方法

注冊(cè)消息方法的作用是將訂閱者注冊(cè)的消息推入到消息隊(duì)列中,因此需要傳遞兩個(gè)參數(shù):消息類型和對(duì)應(yīng)的處理函數(shù),要注意的是,如果推入到消息隊(duì)列是如果此消息不存在,則要?jiǎng)?chuàng)建一個(gè)該消息類型并將該消息放入消息隊(duì)列中,如果此消息已經(jīng)存在則將對(duì)應(yīng)的方法突入到執(zhí)行方法隊(duì)列中。

    //注冊(cè)消息接口
    on: function (type, fn) {
        //如果此消息不存在,創(chuàng)建一個(gè)該消息類型
        if( typeof __message[type] === 'undefined' ){
            // 將執(zhí)行方法推入該消息對(duì)應(yīng)的執(zhí)行隊(duì)列中
            __message[type] = [fn];
        }else{
            //如果此消息存在,直接將執(zhí)行方法推入該消息對(duì)應(yīng)的執(zhí)行隊(duì)列中
            __message[type].push(fn);
        }
    }

發(fā)布消息方法

發(fā)布消息,其功能就是當(dāng)觀察者發(fā)布一個(gè)消息是將所有訂閱者訂閱的消息依次執(zhí)行,也需要傳兩個(gè)參數(shù),分別是消息類型和對(duì)應(yīng)執(zhí)行函數(shù)時(shí)所需要的參數(shù),其中消息類型是必須的。

    //發(fā)布消息接口
    subscribe: function (type, args) {
        //如果該消息沒(méi)有注冊(cè),直接返回
        if ( !__message[type] )  return;
        //定義消息信息
        let events = {
            type: type,           //消息類型
            args: args || {}       //參數(shù)
        },
        i = 0,                         // 循環(huán)變量
        len = __message[type].length;   // 執(zhí)行隊(duì)列長(zhǎng)度
        //遍歷執(zhí)行函數(shù)
        for ( ; i < len; i++ ) {
            //依次執(zhí)行注冊(cè)消息對(duì)應(yīng)的方法
            __message[type][i].call(this,events)
        }
    }

移除消息方法

移除消息方法,其功能就是講訂閱者注銷的消息從消息隊(duì)列中清除,也需要傳遞消息類型和執(zhí)行隊(duì)列中的某一函數(shù)兩個(gè)參數(shù)。這里為了避免刪除是,消息不存在的情況,所以要對(duì)其消息存在性制作校驗(yàn)。

    //移除消息接口
    off: function (type, fn) {
        //如果消息執(zhí)行隊(duì)列存在
        if ( __message[type] instanceof Array ) {
            // 從最后一條依次遍歷
            let i = __message[type].length - 1;
            for ( ; i >= 0; i-- ) {
                //如果存在改執(zhí)行函數(shù)則移除相應(yīng)的動(dòng)作
                __message[type][i] === fn && __message[type].splice(i, 1);
            }
        }
    }

大顯身手

   //訂閱消息
    Observe.on('say', function (data) {
        console.log(data.args.text);
    })
    Observe.on('success',function () {
        console.log('success')
    });
    
    //發(fā)布消息
    Observe.subscribe('say', { text : 'hello world' } )
    Observe.subscribe('success');  

我們?cè)谙㈩愋蜑?say的消息中注冊(cè)了兩個(gè)方法,其中有一個(gè)接受參數(shù),另一個(gè)不需要參數(shù),然后通過(guò) subscribe 發(fā)布saysuccess消息,結(jié)果跟我們預(yù)期的一樣,控制臺(tái)輸出了hello world以及 success

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,612評(píng)論 19 139
  • 設(shè)計(jì)模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計(jì)原則時(shí)需要注意以下幾點(diǎn):a) 高內(nèi)聚、低耦合和單一職能的“沖突”實(shí)際上,這兩者...
    彥幀閱讀 3,890評(píng)論 0 14
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,262評(píng)論 8 265
  • 點(diǎn)擊查看原文 Web SDK 開(kāi)發(fā)手冊(cè) SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個(gè)完善的 IM 系統(tǒng)...
    layjoy閱讀 14,316評(píng)論 0 15
  • 什么是p2p公司_華融道理財(cái) 什么是p2p公司_華融道理財(cái) 什么是p2p公司_華融道理財(cái)
    查暇諗65475閱讀 224評(píng)論 0 0

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