发布订阅模式的代码实现
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);