1. 程式人生 > 其它 >Javacript實現簡單的釋出訂閱模式或觀察者模式的進階版

Javacript實現簡單的釋出訂閱模式或觀察者模式的進階版

/**
* 實現一個簡單的觀察者模式
*/

const shop = {
apple: 5, // 蘋果5元
potato: 2, // 馬鈴薯 2元
tomato: 3, // 西紅柿 3元
orange: 7,
}

/**
* 現在我們有一個便利店的例項物件,目標是需要增加對商品價格的監聽,當商品價格發生變化時,觸發對應的事件。
* 1、小明關注蘋果價格變化
* 2、小剛關注橙子價格變化
* 3、當價格變化時,自動觸發對應的事件
*/

class Pubsub {
constructor() {
}

list = {};

// 監聽方法,新增監聽者,監聽物件,和監聽事件的方法
listen = (key, listener, fn) => {
const { list = {} } = this;
if (!list[key]) {
list[key] = [];
}
list[key].push({ listener, fn });
return () => this.remove(key, listener, fn);
}

// 釋出訊息的方法
publish = (key, price) => {
const { list = {} } = this;
if (list[key]) {
list[key].forEach((item) => {
const { listener, fn } = item;
fn.call(null, listener, price);
})
}
}

// 移除監聽的方法
remove = (key, listener, fn) => {
const { list = {} } = this;
if (!listener) { // 如果沒有傳入監聽人,則移除對該屬性的所有監聽
delete list[key];
return;
}

if (!fn || typeof fn !== 'function') { // 如果沒有傳入fn,則移除此監聽者的所有監聽事件
list[key] = list[key].filter(x => x.listener !== listener);
return;
}

const index = list[key].findIndex(x => x.listener === listener && x.fn === fn);
list[key].splice(index, 1);
if (list[key].length === 0) { // 如果移除監聽後,監聽列表的長度變為0, 則移除這個監聽
delete list[key];
}
}
}

const pubsub = new Pubsub();

const event1 = pubsub.listen('apple', '小明', (listener, price) => {
console.log(`${listener}關注的apple的最新價格是${price}`);
})

const enent2 = pubsub.listen('orange', '小明', (listener, price) => {
console.log(`${listener}關注的orange的最新價格是${price}`);
})

const enent3 = pubsub.listen('orange', '小剛', (listener, price) => {
console.log(`${listener}關注的orange的最新價格是${price}`);
})

const set = (target, key, value, receiver) => {
if (receiver[key] !== value) {
pubsub.publish(key, value);
}
return Reflect.set(target, key, value, receiver);
}

const observable = (obj) => new Proxy(obj, { set });

const newShop = observable(shop);

newShop.apple = 5;

newShop.apple = 6;
/** 小明關注了蘋果的價格,蘋果價格變更將會觸發事件
** console.log將會輸出: 小明關注的apple的最新價格是6元
**/

newShop.tomato = 10;
/** 無人關注西紅柿價格,不會觸發事件 **/

newShop.orange = 11;
/** 小明關注了橙子的價格,橙子價格變更將會觸發事件
** console.log將會輸出: 小明關注的orange的最新價格是11元
**/

/** 小剛關注了橙子的價格,橙子價格變更將會觸發事件
** console.log將會輸出: 小剛關注的orange的最新價格是11元
**/

// 移除小明對app事件的監聽
event1();

newShop.apple = 7;
/** 蘋果監聽已經被移除,無人關注蘋果價格,不會觸發事件 **/

newShop.orange = 12;
/** 小明關注了橙子的價格,橙子價格變更將會觸發事件
** console.log將會輸出: 小明關注的orange的最新價格是12元
**/

/** 小剛關注了橙子的價格,橙子價格變更將會觸發事件
** console.log將會輸出: 小剛關注的orange的最新價格是12元
**/