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

資訊專(zhuān)欄INFORMATION COLUMN

javascript設(shè)計(jì)模式之觀察者模式

Tamic / 1027人閱讀

摘要:下面為學(xué)習(xí)筆記,對(duì)觀察者模式做簡(jiǎn)單實(shí)現(xiàn)。注冊(cè)的事件被觸發(fā)后需要執(zhí)行的動(dòng)作注冊(cè)事件及對(duì)應(yīng)的執(zhí)行動(dòng)作觸發(fā)事件對(duì)比執(zhí)行事件前后的事件列表內(nèi)容觀察者模式在解決類(lèi)的耦合中的應(yīng)用小例子。

這篇筆記主要記錄學(xué)習(xí)思路及收獲,分享出來(lái)拋磚引玉,如有謬誤或優(yōu)化空間,歡迎交流。

要理解觀察者模式,可以類(lèi)比vue中的EventBus,其實(shí)就是一個(gè)全局的觀察者對(duì)象($bus),上面有注冊(cè)事件($bus.on())和發(fā)送事件($bus.emit())的方法,當(dāng)然因?yàn)樾枰獣?huì)注冊(cè)很多事件,所以?xún)?nèi)部還有一個(gè)事件列表屬性_events來(lái)存儲(chǔ)注冊(cè)的事件。下面為學(xué)習(xí)筆記,對(duì)觀察者模式做簡(jiǎn)單實(shí)現(xiàn)。

基于上面的思路,首先要有一個(gè)對(duì)象,它有一個(gè)私有的列表屬性和對(duì)外暴露的兩個(gè)方法

let Observer = (()=>{
    _events:[];
    return {
        retister:()=>{},
        issue:()=>{},
    }
})()

接下來(lái)一步步實(shí)現(xiàn)。

首先,觀察者對(duì)象內(nèi)部要有一個(gè)存儲(chǔ)事件的列表屬性

let Observer = (()=>{
    // 防止事件隊(duì)列暴露而被篡改故將事件容器作為靜態(tài)私有變量保存
    let _events = [];
})()

其次是注冊(cè)事件的register方法,需要兩個(gè)參數(shù):需要觀察的事件名稱(chēng)type和這個(gè)事件被觸發(fā)后具體的執(zhí)行內(nèi)容fn

let Observer = (()=>{
    // 防止事件隊(duì)列暴露而被篡改故將事件容器作為靜態(tài)私有變量保存
    let _events = {};
    return {
        register: (type,fn)=>{
            //如果此消息類(lèi)型不存在則應(yīng)該創(chuàng)建一個(gè)(判斷對(duì)象上是否有某個(gè)屬性)
            // if (typeof(_events[type])==="undefined"){
            if (!(type in _events)){
                _events[type] = [fn];
            } else {//如果此消息類(lèi)型已存在,則直接將對(duì)應(yīng)動(dòng)作推入消息隊(duì)列
                _events[type].push(fn);
            }
        },
    }
})()

再然后就是觸發(fā)事件的issue方法,也需要兩個(gè)參數(shù):要觸發(fā)的事件type及傳遞過(guò)去的參數(shù)arg

let Observer = (()=>{
    // 防止事件隊(duì)列暴露而被篡改故將事件容器作為靜態(tài)私有變量保存
    let _events = {};
    return {
        register: (type,fn)=>{
            //如果此消息類(lèi)型不存在則應(yīng)該創(chuàng)建一個(gè)(判斷對(duì)象上是否有某個(gè)屬性)
            // if (typeof(_events[type])==="undefined"){
            if (!(type in _events)){
                _events[type] = [fn];
            } else {//如果此消息類(lèi)型已存在,則直接將對(duì)應(yīng)動(dòng)作推入消息隊(duì)列
                _events[type].push(fn);
            }
        },
        issue: (type,arg)=>{
            // 如果沒(méi)有此類(lèi)型,返回
            // if (typeof (_events[type]) === "undefined"){
            if (!(type in _events)) {
                return;
            }
            for (let i=0;i<_events[type].length;i++){
                _events[type][i](arg);
            }
        },
    }
})()

最后,可以再加一個(gè)可以移除已監(jiān)聽(tīng)事件的remove方法

let Observer = (()=>{
    // 防止事件隊(duì)列暴露而被篡改故將事件容器作為靜態(tài)私有變量保存
    let _events = {};
    return {
        register: (type,fn)=>{
            //如果此消息類(lèi)型不存在則應(yīng)該創(chuàng)建一個(gè)(判斷對(duì)象上是否有某個(gè)屬性)
            // if (typeof(_events[type])==="undefined"){
            if (!(type in _events)){
                _events[type] = [fn];
            } else {//如果此消息類(lèi)型已存在,則直接將對(duì)應(yīng)動(dòng)作推入消息隊(duì)列
                _events[type].push(fn);
            }
        },
        issue: (type,arg)=>{
            // 如果沒(méi)有此類(lèi)型,返回
            // if (typeof (_events[type]) === "undefined"){
                if (!(type in _events)) {
                return;
            }
            for (let i=0;i<_events[type].length;i++){
                _events[type][i](arg);
            }
        },
        // 此方法可以類(lèi)比document.removerEventListener(evt,fn)
        remove: (type,fn)=>{
            // 如果這個(gè)類(lèi)型的事件存在
            if (_events[type] instanceof Array){
                for (let i = 0; i < _events[type].length; i++) {
                    _events[type][i] === fn && _events[type].splice(i,1);
                }
            }
        },
        // 因?yàn)橥獠揩@取不到私有屬性`_events`,所以臨時(shí)用這個(gè)方法檢查`remove`方法是否生效
        check (){
            console.log("_events事件隊(duì)列",_events);
        }
    }
})()

至此一個(gè)基本的觀察者對(duì)象就寫(xiě)出來(lái)了,接下來(lái)跑一下看效果。

// 注冊(cè)的事件被觸發(fā)后需要執(zhí)行的動(dòng)作
function handler (val){
    console.log("val:",val*2);
}

// 注冊(cè)事件及對(duì)應(yīng)的執(zhí)行動(dòng)作
Observer.register("eventName",handler);

// 觸發(fā)事件
function test (){
    Observer.issue("eventName",5); //10
    // 對(duì)比執(zhí)行remove事件前后的事件列表內(nèi)容
    Observer.check();
    Observer.remove("eventName",fn);
    observer.check();
}

觀察者模式在解決類(lèi)的耦合中的應(yīng)用小例子。想象一下課堂上老師提問(wèn),學(xué)生回答問(wèn)題的場(chǎng)景。老師提問(wèn)的問(wèn)題名稱(chēng)相當(dāng)于發(fā)出的事件,如果學(xué)生聽(tīng)到這個(gè)問(wèn)題(事先注冊(cè)了這個(gè)問(wèn)題名稱(chēng)),那么便會(huì)回答(響應(yīng)事件的動(dòng)作)。

學(xué)生類(lèi):

let Student = function (result) {
    // 問(wèn)題答案
    this.result = result;
    // 回答的動(dòng)作
    this.answer = ()=>{
        console.log("答案",this.result);
    }   
}
Student.prototype.listen = function(question){
    Observer.register(question,this.answer);
}
Student.prototype.sleep = function (question) {
    Observer.remove(question,this.answer);
    console.log("這個(gè)問(wèn)題我聽(tīng)不到聽(tīng)不到~");
}

教師類(lèi):

let Teacher = function (){}
// 對(duì)某一個(gè)問(wèn)題發(fā)出問(wèn)題
Teacher.prototype.ask = function (question) {
    Observer.issue(question);
}

執(zhí)行:

let student1 = new Student("學(xué)生1回答問(wèn)題");
let student2 = new Student("學(xué)生2回答問(wèn)題");
let student3 = new Student("學(xué)生3:呼嚕呼嚕~");
student1.listen("雞生蛋還是蛋生雞?");
student2.listen("雞生蛋還是蛋生雞?");
student3.listen("雞生蛋還是蛋生雞?");
let teacher = new Teacher();
// 老師發(fā)問(wèn)
function test () {
    teacher.ask("雞生蛋還是蛋生雞?");
}
//答案 學(xué)生1回答問(wèn)題
//es5觀察者.html:68 答案 學(xué)生2回答問(wèn)題
//es5觀察者.html:68 答案 學(xué)生3:呼嚕呼嚕~

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

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

相關(guān)文章

  • JavaScript設(shè)計(jì)模式發(fā)布-訂閱模式察者模式)-Part1

    摘要:設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記。發(fā)布訂閱模式又叫觀察者模式,它定義了對(duì)象之間的一種一對(duì)多的依賴(lài)關(guān)系。附設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式數(shù)據(jù)結(jié)構(gòu)和算法系列棧隊(duì)列優(yōu)先隊(duì)列循環(huán)隊(duì)列設(shè)計(jì)模式系列設(shè)計(jì)模式之策略模式 《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》讀書(shū)筆記。 發(fā)布-訂閱模式又叫觀察者模式,它定義了對(duì)象之間的一種一對(duì)多的依賴(lài)關(guān)系。當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)它的對(duì)象都將得到通知。 例...

    muzhuyu 評(píng)論0 收藏0
  • javascript察者模式

    摘要:觀察者模式應(yīng)用場(chǎng)景場(chǎng)景一當(dāng)觀察的數(shù)據(jù)對(duì)象發(fā)生變化時(shí)自動(dòng)調(diào)用相應(yīng)函數(shù)。比如的雙向綁定場(chǎng)景二每當(dāng)調(diào)用對(duì)象里的某個(gè)方法時(shí)就會(huì)調(diào)用相應(yīng)訪問(wèn)邏輯。 觀察者模式 應(yīng)用場(chǎng)景: 場(chǎng)景一: 當(dāng)觀察的數(shù)據(jù)對(duì)象發(fā)生變化時(shí), 自動(dòng)調(diào)用相應(yīng)函數(shù)。比如 vue 的雙向綁定;場(chǎng)景二: 每當(dāng)調(diào)用對(duì)象里的某個(gè)方法時(shí), 就會(huì)調(diào)用相應(yīng)訪問(wèn)邏輯。比如給測(cè)試框架賦能的 spy 函數(shù); 場(chǎng)景一: 雙向綁定 Object.defi...

    Riddler 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式發(fā)布-訂閱模式察者模式)-Part2

    摘要:設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記。看此文章前,建議先看設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式在中,已經(jīng)介紹了什么是發(fā)布訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布訂閱模式。 《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》讀書(shū)筆記。 看此文章前,建議先看JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式(觀察者模式)-Part1 在Part1中,已經(jīng)介紹了什么是發(fā)布-訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布-訂閱模式。但是,就Part1...

    Charlie_Jade 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式發(fā)布-訂閱模式察者模式)-Part2

    摘要:設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記。看此文章前,建議先看設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式在中,已經(jīng)介紹了什么是發(fā)布訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布訂閱模式。 《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》讀書(shū)筆記。 看此文章前,建議先看JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式(觀察者模式)-Part1 在Part1中,已經(jīng)介紹了什么是發(fā)布-訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布-訂閱模式。但是,就Part1...

    chemzqm 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<