觀察者模式又被稱爲發佈-訂閱模式,是設計模式中的一種行爲型模式;前端
定義:vue
觀察者模式定義了一種一對多的對象依賴關係,當被依賴的對象的狀態發生了改變,全部依賴它的對象都會獲得通知;設計模式
白話解釋:數組
假如你去蘋果專賣店買最新款的iphone11,由於iphone11剛出來不久,正處旺季,供貨不足;當你去專賣店的時候,店員告訴你暫時沒貨了,可是你能夠留下你的聯繫方式,若是貨到了,會第一時間通知;固然你確定不會天天都去專賣店問iphone11到貨沒有,也不會每天給專賣店打電話,由於你有你本身的工做和生活,不可能有那麼多閒暇時間;因此此時,店員讓你留下聯繫方式,到貨了第一時間通知你,不會給你帶來麻煩,而你只須要等着專賣店的電話便可;而這種方法就是一種典型的觀察者模式;
瀏覽器
首先咱們仍是來分析一下:app
1.訂閱方法:咱們把聯繫方式給專賣店店員是屬於一種消息訂閱的消息,由於只有這樣你才能及時的知道iphone11到貨了,全部咱們須要一個訂閱行爲的具體方法;框架
2.預訂列表:要知道iphone11是屬於新版iphone,因此確定不會是隻有你一我的去預訂,因此店員爲了方便統計還須要一個預訂列表來統計全部的預訂者的聯繫方式以及預訂手機版本信息,因此咱們這裏先給它定義爲一個對象;key表明是預訂者的聯繫方式,value表明預訂手機版本信息;iphone
3.發佈方法:當iphone11到貨的時候,專賣店確定要根據預訂列表來進行統一發布消息("iphone11到貨了,你們快來搶!!!"),因此專賣店須要一個發佈方法來實行具體的發佈行爲;、函數
4.取消訂閱:萬物相對,能訂閱確定就能取消訂閱;在等待iphone11到貨通知的時候,你急着用手機,因此直接買了華爲的某款,因此iphone11暫時對你來講需求不大,由於你已經有了手機因此專賣店的iphone11是否到貨對你來講沒有任何意義了;因此此時你不想被打擾,須要取消訂閱消息;因此咱們須要一個取消訂閱方法來實現具體的取消訂閱的行爲;學習
觀察者模式的應用場景:
一、DOM事件
若是你是一個前端開發人員,無論你讀這篇文章以前是否已經瞭解觀察者模式,可是我能確定你已經用過觀察者模式;
document.body.addEventListener('click', function() { console.log('hello world!'); });
這段代碼看着眼熟嗎?是的,這是一個DOM事件的監聽;咱們經過給body訂閱click事件(click至關於上面的訂閱方法),由於瀏覽器並不知道你何時點擊鼠標,因此等你觸發click事件的時候纔會觸發函數給你發佈通知(發佈方法);DOM事件就是一個觀察者模式的實現;
二、vue雙向綁定v-model
咱們做爲前端開發人員,確定知道vue是一個MVVM模式的框架;vue的核心就是雙向綁定,那麼雙向綁定的實現實際上就是一種觀察者模式;由於你首先綁定了一個數據以後(訂閱方法),瀏覽器並不知道你何時修改,你頁面上全部綁定了該數據或者依賴該數據的節點其實就是一個預訂列表,只有等你修改了該數據的值的時候,vue纔會通知(發佈方法)到依賴該數據的方法/數據進行相應的操做或刷新;
固然觀察者模式毫不僅限於這倆種實現場景,在咱們的生活中、業務場景中有不少觀察者模式的示例,以前咱們第一篇工廠模式介紹設計模式的時候就說過了,設計模式是一種解決問題的思路而非一種固定的公式,那麼咱們怎麼實現觀察者模式呢?
觀察者模式的實現:
//定義商家 var merchants = {}; //定義預訂列表 merchants.orderList = {}; //將增長的預約者添加到預訂列表中 (訂閱方法) merchants.listen = function(id,info){ //若是存在 if(!this.orderList[id]){ // (預訂列表) this.orderList[id] = []; } // 將用戶的預約的產品信息存入到數組中 this.orderList[id].push(info); } //發佈信息(發佈方法) merchants.publish = function(){ var id = Array.prototype.shift.call(arguments); var infos = this.orderList[id]; if(!infos || infos.length === 0){ console.log("您尚未預約信息"); return false; } for(var i = 0;i < infos.length;i++){ console.log("預約成功"); console.log("尊敬的用戶:") infos[i].apply(this,arguments); console.log("到貨了"); } } //取消訂閱 merchants.remove = function(id,fn){ var infos = this.orderList[id]; if(!infos){ return false} if(!fn){ console.log(123); }else{ for(var i = 0;i < infos.length;i++){ if(infos[i] === fn){ infos.splice(i,1); } } } } let customeA = function(){ console.log("黑色尊享版一臺"); } merchants.listen("15172103336",customeA); merchants.remove("15172103336",customeA); merchants.publish("15172103336");
上面的代碼稍微有點長,不過沒有很難;首先咱們是定義了一個對象是做爲商家,而後定義了一個空的對象做爲預訂列表,再一步步的實現咱們的訂閱方法和發佈以及取消訂閱的方法;邏輯不復雜,可是有一些語法須要講解一下:
發佈方法中的var id = Array.prototype.shift.call(arguments);這句的意思是將merchants.publish("15172103336");方法調用的時候第一個參數返回給它而後複製爲id,因此其實此時的id值爲」15172103336「;
infos[i].apply(this,arguments);這個方法也不是特別好理解,首先infos裏裝的是預訂者的手機號碼以及手機版本信息,因此咱們infos[i].apply(this,arguments);這個方法其實就是將"15172103336"對應的手機版本信息函數進行調用了一遍;實際上等於infos[i](arguments);
觀察者模式不論是在前端領域仍是在現實生活中的應用都是有很常見的場景,學好觀察者模式有利用咱們學習vue的源碼知識,固然不只限於此,因此觀察者模式值得咱們好好學習,一句話:"你品,你細品!" 今天付出的努力,在往後總會換成工資來回報你的!哈哈哈