JavaScript 发布订阅模式实现

来自迅雷前端的一道笔试题

实现一个EventEmitter类,实现以下方法:

1.emitter.on(name,fn) //订阅name事件,监听函数为fn,可多次订阅

2.emitter.once(name,fn) //功能与on类似,但监听函数为一次性的,触发后自动移除

3.emitter.emit(name,data1,data2,...,datan) //发布name事件,所有订阅该事件的监听函数被触发,data1,...,datan作为参数传给监听函数,若有多个函数,按照顺序执行

4.emitter.remove(name,fn) //移除name事件的监听函数fn

代码实现:

//发布订阅模式
	function EventEmitter(){
		//缓存列表,存放订阅者列表
		var list = [];
		var instance;
		//订阅事件name,type = 0表示永久订阅 =1表示一次订阅
		var on = function(name,fn,type = 0){
			//判断事件是否曾被订阅
			if(!list[name]){
				list[name] = [];
			}
			list[name].push([fn,type]);//监听函数插入该事件列表
		};
		//订阅一次触发后删除
		var once = function(name,fn,type = 1){
			on(name,fn,type);
		};
		//发布
		var emit = function(name){
			var fns = list[name];//取出事件
			//获取参数列表
			var args = [].slice.call(arguments,1);
			//判断监听函数是否存在
			if (!fns || fns.length == 0) {
				return;
			}
			for(var i =0;i<fns.length,fn = fns[i++];){
				fn[0].apply(this,args);
				if(fn[1] == 1){
					remove(name,fn[0],1);
				}
			}
		};
		//删除事件
		var remove = function(name,fn,type = 0){
			if(!name){
				return;
			}
			var fns = list[name];
			//未传入监听函数,取消全部
			if(!fn){
				list[name] = [];
			}else{
				for(var i =0;i<fns.length,fn1 = fns[i];i++){
					//找到对应函数,删除之
					if(fn === fn1[0]&&type ===fn1[1]){
						fns.splice(i,1);
					}
				}
			}
		};
		return {
			on:on,
			once:once,
			emit:emit,
			remove,remove
		}
	}
	var emitter = new EventEmitter();
	var log = console.log;
	emitter.on('someTask',log);
	emitter.emit('someTask',1);//1
	emitter.emit('someTask',1,2);//1,2
	emitter.once('someTask',log);
	emitter.emit('someTask',1);//1
	emitter.emit('onceTask',1);//不输出
	emitter.remove('someTask',log);
	emitter.emit('someTask',1);//不输出

猜你喜欢

转载自blog.csdn.net/sinat_41871344/article/details/82708684
今日推荐