javascript中的发布订阅模式的学习和demo实践
1.发布订阅模式最关键的就是发布的实现和订阅的实现,首先,声明一个构造函数,我们这里采用es6的写法:
class Mode1 {
constructor(){
this.eventList = [
// {name: 123, fun: [fun1, fun2]}
]
};
}
eventList这个数组用来存放所有的事件,同一类型的事件放在一个对象中,name是事件的名字。Fun是一个放该事件所有处理函数的数组,在发布该事件的时候,会依次触发所有该事件下的事件处理函数。
2.接下来 我们在这个类中写一个发布事件的函数
release(){
for(let i = 0;i < this.eventList.length;i++){
if(this.eventList[i].name === arguments[0]){
for(let t = 0;t < this.eventList[i].fun.length;t++){
this.eventList[i].fun[t].apply(this,Array.prototype.slice.call(arguments,1));
}
}
}
};
现在发布事件时,先循环遍历eventList数组中是否已经订阅过该事件名称的事件处理函数
this.eventList[i].name === arguments[0]
如果找到的对应名称,就循环执行该名称下所有的事件处理函数,这里注意,要用apply控制一下this指向,并且在传参的时候,要将第一个参数也就是arguments[0]给去掉;这里有个小技巧,用Array.prototype[数组方法明].call的方式可以让伪数组使用Array构造函数原型上的方法。
3.接下来是订阅事件的事件处理函数
add(evName,cb){
let findStatus = false;
for(let i = 0;i < this.eventList.length;i++){
if(this.eventList[i].name === evName){
this.eventList[i].fun.push(cb);
findStatus = true;
break;
}
}
if(!findStatus){
this.eventList.push({
name: evName,fun: [cb]
})
}
}
首先是判断在eventList数组中是否已经订阅过同名的事件,如果订阅过,就直接往对应的数组中的对象的fun数组中push,然后break退出循环,如果没有订阅过同名事件,就新建一个对象{ name: evName,fun: [cb] }来存放。
我们可以试用一下
var modeTest = new Mode1();
modeTest.add('study',function(time,way){
console.log(`i go to school at ${time}, by ${way}`);
});
modeTest.add('study',function(time,way){
console.log(`i go to school by ${way} at ${time}`);
});
modeTest.add('back',function(time,way){
console.log(`i go to home by ${way} at ${time}`);
});
modeTest.add('back',function(time,way){
console.log(`i go to home at ${time}, by ${way} `);
});
modeTest.release('study','今天','腿');
modeTest.release('back','下午','GTR');
输出结果:
i go to school at 今天 by 腿
i go to school by 腿 at 今天
i go to home by GTR at 下午
i go to home at 下午 by GTR
最后附上完整代码:
class Mode1 {
constructor(){
this.eventList = [
// {name:123,fun:[fun1,fun2]}
]
};
release(){
for(let i = 0;i < this.eventList.length;i++){
if(this.eventList[i].name === arguments[0]){
for(let t = 0;t < this.eventList[i].fun.length;t++){
this.eventList[i].fun[t].apply(this,Array.prototype.slice.call(arguments,1));
}
}
}
};
add(evName,cb){
let findStatus = false;
for(let i = 0;i < this.eventList.length;i++){
if(this.eventList[i].name === evName){
this.eventList[i].fun.push(cb);
findStatus = true;
break;
}
}
if(!findStatus){
this.eventList.push({
name: evName,fun: [cb]
})
}
}
}
var modeTest = new Mode1();
modeTest.add('study',function(time,way){
console.log(`i go to school at ${time}, by ${way}`);
});
modeTest.add('study',function(time,way){
console.log(`i go to school by ${way} at ${time}`);
});
modeTest.add('back',function(time,way){
console.log(`i go to home by ${way} at ${time}`);
});
modeTest.add('back',function(time,way){
console.log(`i go to home at ${time}, by ${way} `);
});
modeTest.release('study','今天','腿');
modeTest.release('back','下午','GTR');
新人前端记录学习过程,如有错误的地方还请海涵和指导,欢迎讨论,谢谢
转载自:https://juejin.cn/post/6987040591167094814