实现思路
- 创建一个对象;
- 在该对象上创建一个调度中心,实际上是一个缓存列表;
- on 方法用来把函数 fn 都加到缓存列表中,也即订阅者注册事件到调度中心;
- emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码);
- off 方法可以根据 event 的值取消订阅;
- once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
JavaScript代码实现
let eventEmitter = {
//缓存列表
list:{},
// 订阅
on(event, fn){
let _this = this
// 如果对象中没有对应的event的值,也就说明没有订阅过,就给event创建个缓存列表
// 如果对象中有对应的event的值,把fn添加到对应的event的缓存列表里面
(_this.list[event] || this.list[event] = []).push(fn)
},
off(event, fn){
let _this = this;
let fns = _this.list[event];
//如果缓存列表中没有相应的 fn,则返回fasle
if(!fns) return false;
if(!fn){
//如果没有传 fn 的话,就会将event值对应缓存列表中的 fn 都清空
fns && (fns.length = 0)
}else{
for (let i = 0, cbLen = fns.length; i < cbLen; i++){
cb = fns[i];
if(cb === fn || cb.fn === fn){
fns.splice(i,1);
break;
}
}
}
return _this
},
emit(){
let _this = this;
// 第一个参数是对应的 evnet 值,直接用数组的shift
let event = [].shift.call(arguments),
fns = _this.[event];
// 如果缓存列表里面没有fn 就返回false
if(!fns || fns.length === 0){
return false
}
fns.forEach(fn => {
fn.apply(_this, arguments)
})
return _this;
},
//监听一次
once (event, fn){
// 先绑定,调用后删除
let _this = this;
function on(){
_this.off(event, on);
}
on.fn = fn;
_this.on(event, on);
return _this;
}
}