兩種模式存在一定區別
一、觀察者模式(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();
});
}
}
