1、前言html
發佈訂閱模式,基於一個主題/事件通道,但願接收通知的對象(稱爲subscriber)經過自定義事件訂閱主題,被激活事件的對象(稱爲publisher)經過發佈主題事件的方式被通知。數組
就和用戶訂閱微信公衆號道理同樣,一個公衆號能夠被多個用戶同時訂閱,當公衆號有新增內容時候,只要發佈就行了,用戶就能接收到最新的內容。微信
js中的事件監聽機制就是一種觀察者模式。app
2、和觀察者模式的區別函數
觀察者模式:一個對象(稱爲subject)維持一系列依賴於它的對象(稱爲observer),將有關狀態的任何變動自動通知給它們(觀察者)。this
一、Observer模式要求觀察者必須訂閱內容改變的事件,定義了一個一對多的依賴關係;
二、Publish/Subscribe模式使用了一個主題/事件通道,這個通道介於訂閱着與發佈者之間;
三、觀察者模式裏面觀察者「被迫」執行內容改變事件(subject內容事件);發佈/訂閱模式中,訂閱着能夠自定義事件處理程序;
四、觀察者模式兩個對象之間有很強的依賴關係;發佈/訂閱模式兩個對象之間的耦合讀底spa
這是一個簡單的實現,主要是建立一個對象,有三個屬性(容器,訂閱方法,發佈方法)。將訂閱者放入容器,發佈,觸發容器內的函數。prototype
(function(){ // function Public(){ //存放訂閱者的容器 this.subscribers=[]; //添加訂閱者 this.addSubscribers=function(fn){ let isExit = this.subscribers.some(function(sub){ return fn == sub; }) if(!isExit){ this.subscribers.push(fn); } return this; } //發佈消息 this.deliver = function(data){ this.subscribers.forEach(function(fn){ fn(data); }) return this; } } let a = function(data){ console.log("a:"+data); } let b = function(data){ console.log("b:"+data); } let c = function(data){ console.log("c:"+data); } var pub = new Public(); pub.addSubscribers(a).addSubscribers(b).addSubscribers(c); pub.deliver("消息"); })()
二、能夠看到觀察者模式有以下優勢code
a、每個訂閱者都是相互獨立的只和發佈者有關係,與發佈者是一對多的關係,也能夠是一對一的關係。
b、每個訂閱者能夠根據本身的需求來調用,而不影響其它訂閱者
c、與第一種方式相比,第二種方式的代碼可讀性、可維護性強;server
這是一個完整的實現
(function(win){ function Public(){ this.handlers={}; } Public.prototype = { //訂閱事件 on:function(eventType,eventHandle){ var self = this; if(!(eventType in self.handlers)){ self.handlers[eventType] = []; } self.handlers[eventType].push(eventHandle); return this; }, emit:function(eventType){ //若是調用函數傳了多個參數,eventType指第一個參數,arguments是一個對象,參數序號是key指,同時也給他length //看起來像數組,其實不是數組。 var self = this; //去除第一個事件類型的參數,使用call改變this指向 //使用slice的對象須要由length屬性,因此arguments才能使用成功。 var handleArgs = Array.prototype.slice.call(arguments,1); console.log(handleArgs); for (var i =0; i<self.handlers[eventType].length;i++) { //使用apply,訂閱者的調用對象就是Public,不適用就是數組對象。 self.handlers[eventType][i].apply(self,handleArgs); } return this; }, off:function(eventType,eventHandle){ var currentEvent = this.handlers[eventType]; var len = 0; if(currentEvent){ len = currentEvent.length;
if(eventHandle == undefined){ currentEvent[eventType] = []; }else{ for (var i = len-1;i >= 0;i--) { if(currentEvent[i] == eventHandle){ currentEvent.splice(i,1); } } } } } } var a = function(data){ console.log(this); console.log("a"+data); } var b =function(data){ console.log("b"+data); } var pub = new Public(); pub.on("click",a).on("click",b); pub.emit("click","xiaoxi"); })(window)
參考博主的文章:https://www.cnblogs.com/leaf930814/p/9014200.html