实现分析:
- 要有个事件储存中心:用来存储 不同订阅者及对应的回调函数列表;
- on方法:往事件储存中心推送订阅者的回调函数;
- off方法:解除订阅;
- emit方法:派发执行同一订阅下的所有回调函数;
- once方法:只执行一次,执行结束后立即off掉此订阅;
代码如下:
class Eventhub{
constructor() {
this.eventsCenter = {};
}
on(key, callBack){
// 添加订阅
if(this.eventsCenter.hasOwnProperty(key)){
this.eventsCenter[key].push(callBack);
}else {
this.eventsCenter[key] = [callBack]
}
}
off(key, callBack){
// 删除当前订阅下的 此回调函数并且在此订阅无任何回调后,删除此订阅;
if(this.eventsCenter.hasOwnProperty(key)){
const curCallbackList = this.eventsCenter[key]
this.eventsCenter[key] = curCallbackList.filter(eachCallback=>eachCallback !== callBack)
if (!curCallbackList.length) delete this.eventsCenter[key];
}
}
emit(key, ...arg){
// 派发事件,并通过apply将this,arguments传入到回调函数中
const list = this.eventsCenter[key];
if(list?.length){
list.forEach(eachFun => eachFun.apply(this,[...arg]));
}
}
once(key, callBack){
// 订阅一次事件,这里注意 on 和 off要同一个引用,后续才可以将此次订阅off掉
function fun(){
callBack();
this.off(key, fun)
}
this.on(key, fun)
}
}
测试部分:
const demo = new Eventhub()
function test2(){
console.log('a--> case2')
}
demo.on('a',()=>{
console.log('a--> case1')
})
demo.on('a', test2)
// 此时a订阅下,执行case1, case2回调
demo.emit('a');
demo.off('a', test2);
// 此时a订阅下,只执行case1, case2已被解除
demo.emit('a');
demo.once('a', ()=>{
console.log('a--> once')
})
// 此时a订阅下,执行case1, once 两次回调
demo.emit('a');
setTimeout(()=>{
// 此时a订阅下,只执行case1, once 只执行一次
demo.emit('a');
},1000)
以上仅为自己理解,欢迎私信沟通探讨喔!!!