兩種模式存在一定區別
一、觀察者模式(Observer)
觀察者模式指的是一個對象(Subject)維持一系列依賴於它的對象(Observer),當有關狀態發生變更時 Subject 對象則通知一系列 Observer 對象進行更新。
在觀察者模式中,Subject 對象擁有添加、刪除和通知一系列 Observer 的方法等等,而 Observer 對象擁有更新方法等等。
// 定義一個主體對象 class Subject { constructor() { this.Observers = []; } add(observer) { //添加 this.Observers.push(observer) } remove(observer) {//移除 this.Observers.filter(item => item === observer); } notify() { this.Observers.forEach(item => { item.update(); }) } } //定義觀察着對象 class Observer { constructor(name) { this.name = name; } update() { console.log(`my name is:${this.name}`); } } //測試 let sub = new Subject(); let obs1 = new Observer('leaf111'); let obs2 = new Observer('leaf222'); sub.add(obs1); sub.add(obs2); sub.notify();
上述代碼中,我們創建了 Subject 對象和兩個 Observer 對象,當有關狀態發生變更時則通過 Subject 對象的 notify 方法通知這兩個 Observer 對象,這兩個 Observer 對象通過 update 方法進行更新。
二、發布訂閱模式(Publisher && Subscriber)
發布訂閱模式指的是希望接收通知的對象(Subscriber)基於一個主題通過自定義事件訂閱主題,被激活事件的對象(Publisher)通過發布主題事件的方式通知各個訂閱該主題的 Subscriber 對象。
let pubSub = { subs: [], subscribe(key, fn) { //訂閱 if (!this.subs[key]) { this.subs[key] = []; } this.subs[key].push(fn); }, publish(...arg) {//發布 let args = arg; let key = args.shift(); let fns = this.subs[key]; if (!fns || fns.length <= 0) return; for (let i = 0, len = fns.length; i < len; i++) { fns[i](args); } }, unSubscribe(key) { delete this.subs[key] } } //測試 pubSub.subscribe('name', name => { console.log(`your name is ${name}`); }) pubSub.subscribe('gender', gender => { console.log(`your name is ${gender}`); }) pubSub.publish('name', 'leaf333'); // your name is leaf333 pubSub.publish('gender', '18'); // your gender is 18
三、區別
如上圖所示:
1、在觀察者模式中,觀察者是知道Subject的,Subject一直保持對觀察者進行記錄。然而,在發布訂閱模式中,發布者和訂閱者不知道對方的存在。它們只有通過消息代理進行通信。
2、在發布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。
四、vue中的作用
Vue會遍歷實例的data屬性,把每一個data都設置為訪問器,然后在該屬性的getter函數中將其設為watcher,在setter中向其他watcher發布改變的消息。
//遍歷傳入實例的data對象的屬性,將其設置為Vue對象的訪問器屬性 function observe(obj,vm){ Object.keys(obj).forEach(function(key){ defineReactive(vm,key,obj[key]); }); } //設置為訪問器屬性,並在其getter和setter函數中,使用訂閱發布模式。互相監聽。 function defineReactive(obj,key,val){ //這里用到了觀察者模式,它定義了一種一對多的關系,讓多個觀察者監聽一個主題對象,這個主題對象的狀態發生改變時會通知所有觀察者對象,觀察者對象就可以更新自己的狀態。 //實例化一個主題對象,對象中有空的觀察者列表 var dep = new Dep(); //將data的每一個屬性都設置為Vue對象的訪問器屬性,屬性名和data中相同 //所以每次修改Vue.data的時候,都會調用下邊的get和set方法。然后會監聽v-model的input事件,當改變了input的值,就相應的改變Vue.data的數據,然后觸發這里的set方法 Object.defineProperty(obj,key,{ get: function(){ //Dep.target指針指向watcher,增加訂閱者watcher到主體對象Dep if(Dep.target){ dep.addSub(Dep.target); } return val; }, set: function(newVal){ if(newVal === val){ return } val = newVal; //console.log(val); //給訂閱者列表中的watchers發出通知 dep.notify(); } }); } //主題對象Dep構造函數 function Dep(){ this.subs = []; } //Dep有兩個方法,增加訂閱者 和 發布消息 Dep.prototype = { addSub: function(sub){ this.subs.push(sub); }, notify: function(){ this.subs.forEach(function(sub){ sub.update(); }); } }