zoukankan      html  css  js  c++  java
  • 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元
    **/


  • 相关阅读:
    全志A10_linux3.0内核编译记录
    C#使用Socket登陆WordPress源码
    UIKeyboardType键盘
    浅谈 iOS 版本号
    学习软件开发应该看的书
    NSPredicate的用法
    ios 技巧总结(不断更新)
    RSA 加解密
    GCD下的几种实现同步的方式
    iOS事件处理
  • 原文地址:https://www.cnblogs.com/liquanjiang/p/15434339.html
Copyright © 2011-2022 走看看