发布订阅模式的代码实现

let _subscribe = function() {
    class Sub {
        constructor() {
            // 创建一个事件池,用来存储后期需要执行的方法
            this.$pond = [];
        }

        //向事件池中追加方法(重复处理)
        add(func) {
            let flag = this.$pond.some(item => {
                return item === func;
            });
            if(!flag) this.$pond.push(func);
        }

        //从事件池中移除方法
        remove(func) {
            let $pond = this.$pond;
            for(let i=0; i<$pond.length; i++) {
                let item = $pond[i];
                if(item === func) {
                    //移除,但是不能这样写,这样会导致数组塌陷问题,原因看下图
                    //移除不能真移除,因为移除后就break了,肯定会发生数组塌陷问题,只能把当前项赋值为null
                    // $pond.splice(i, 1);
                    $pond[i] = null;
                    break;
                }
            }
        }

        //通知事件池中的方法,按照顺序依次执行
        fire(...args) {
            let $pond = this.$pond;
            for(let i=0; i<$pond.length; i++) {
                let item = $pond[i];
                if(typeof item !== 'function') {
                    $pond.splice(i, 1);
                    i--;
                    continue;
                }
                item.call(this, ...args);
            }
        }
    }

    return function subscribe() {
        return new Sub();
    }
}();

发生数组塌陷的原因:

测试代码:

let pond = _subscribe();
document.querySelector('.submit').onclick = function(e) {
    pond.fire(e);
}
let fn1 = function() {
	console.log(1);
}
let fn2 = function() {
    console.log(2);
    pond.remove(fn1);
}
pond.add(fn1);
pond.add(fn1);
pond.add(fn2);
let fn3 = function() {
    console.log(3);
}
let fn4 = function(e) {
    console.log(4, e);
}
pond.add(fn3);
pond.add(fn4);
posted @ 2021-03-05 17:28  Hhhighway  阅读(229)  评论(0编辑  收藏  举报