javascript中的发布订阅模式的学习和demo实践

806 阅读2分钟

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');

新人前端记录学习过程,如有错误的地方还请海涵和指导,欢迎讨论,谢谢