概述
发布订阅模式,主要围绕一个事件池来实现,在事件池中添加事件类型和对应的函数,这样在触发事件时就可以调用所有的方法了
代码实现
(function(){
//每个实例都有一个池子
class Sub{
costructor(){
this.pond={}
}
//向事件池中添加方法
$on(type,func){
//检测对象事件池中是否有该type如果美有添加并赋值[]
this.pond[type]?null:this.pond[type]=[]
let arr=this.pond[type] //拿到type的数组
//判断数组中用没有相同的方法,如果有就不添加
arr.includes(func)?null:arr.push(func)
}
//从事件池中移除方法
$off(type,func){
let typeArr= this.pond[type]
if(!typeArr)return;
this.pond[type]=typeArr.filter(item=>{
return item!==func
})
}
$emit(type,...args){
let typeArr=this.pond[type]
if(!typeArr)return
for(let i;i<typeArr.length;i++){
if(typeArr[i]==null){
typeArr.splice(i,1)
i--
continue
}
typeArr[i](...args)
}
}
}
return function subscribe(){
return new Sub
}
})()
总结
每一个事件池都是Sub类的实例,实例中的bond属性就是池子,本身是个对象,对象中存放各个类型对应的函数,类中设置公共方法off移除函数,$emit调用相应type值所用方法
数组塌陷问题
当调用$emit执行所用函数时如果有函数是操作删除(splice)正在遍历执行的数组时,会造成数组塌陷(删除元素后面的元素前移,造成一些函数不会执行)
解决
在操作时把要删除的数组元素设为null(用null占位),在$emit函数中,对设置为null的位置删除并把i-- 或者执行的函数每次都是经过深拷贝原数组得来的,这样在执行所有函数,有的函数删除当前数组元素时,循环执行的数组不变,