发布订阅设计模式

209 阅读1分钟

发布订阅设计模式可以理解为制作一张计划表和执行计划

比如:张三要结婚了

计划表:把结婚当天要做的事情一件件都列举出来

结婚时:按照计划表中的计划一件件的去执行即可

发布订阅(按照了DOM2事件池的机制)

1.创建事件池

2.向事件池中追加方法/移除方法

3.通知事件池中的方法执行 事件池的机制有两种,一个是以数组为事件池,往数组里添加对象,每个对象里有事件名称与事件方法

[{	everyType:'marry',    func:fn1},,,]

第二种以Object为事件池,以事件名称为键,方法组成的数组为值

{
	"marry":[fn1,fn2],
    "baby":[],
    ...
}

下面我们来实现一下这个发布订阅的流程

(function () {
    const hasOwn = Object.prototype.hasOwnProperty;
    class Sub {
        // 创建事件池
        pond = {};
        // SUB.PROTOTYPE
        //添加/订阅
        on(type, func) {
            let pond = this.pond,
                listeners;
            !hasOwn.call(pond, type) ? pond[type] = [] : null;
            listeners = pond[type];
            !listeners.includes(func) ? listeners.push(func) : null;
        }
        //移除
        off(type, func) {
            let pond = this.pond,
                listeners = pond[type] || [];
            if (listeners.length === 0) return;
            for (let i = 0; i < listeners.length; i++) {
                if (listeners[i] === func) {
                    // listeners.splice(i, 1); //=>会导致数组塌陷
                    listeners[i] = null;
                    return;
                }
            }
        }
        //执行/发布
        fire(type, ...params) {
            let pond = this.pond,
                listeners = pond[type] || [];
            if (listeners.length === 0) return;
            for (let i = 0; i < listeners.length; i++) {
                let itemFunc = listeners[i];
                if (typeof itemFunc !== "function") {
                    listeners.splice(i, 1);
                    i--;
                    continue;
                }
                itemFunc(...params);
            }
        }
    }

    window.subscribe = function subscribe() {
        return new Sub();
    };
})();