观察者模式之ES6实现(二)
一、问题描述
实现一个EventEmitter类,这个类包含以下方法:
on(监听事件,该事件可以被触发多次)
once(也是监听事件,但只能被触发一次)
fire(触发指定的事件)
off(移除指定事件的某个回调方法或者所有回调方法)
class EventEmitter {
/**请补充你的代码***/
}
const event = new EventEmitter()
const drink = (person) => {
console.log(person + '喝水')
}
event.on('drink', drink)
event.on('eat', (person) => {
console.log(person + '吃东西')
})
event.once('buy', (person) => {
console.log(person + '买东西')
})
event.fire('drink', '我') // 我喝水
event.fire('drink', '我') // 我喝水
event.fire('eat', '其它人') // 其它人吃东西
event.fire('eat', '其它人') // 其它人吃东西
event.fire('buy', '其它人') //其它人买东西
event.fire('buy', '其它人') //这里不会再次触发buy事件,因为once只能触发一次
event.off('eat') //移除eat事件
event.fire('eat', '其它人') //这里不会触发eat事件,因为已经移除了
二、问题分析
这题其实就是实现发布-订阅模式了,难点在于怎样实现once事件,即只触发一次。其实也就是要实现两种类型的事件,我们可以用不同的对象去保存这两种类型的事件,然后在fire的时候,这两种事件都要被处理即可。
三、参考链接
https://github.com/Olical/EventEmitter
四、解决方案
class EventEmitter {
constructor() {
this.queue = {} //可触发多次的事件
this.onceQueue = {} //只能触发一次的事件
}
on(event, fn) { //监听事件,可以触发多次
if (!this.queue[event]) this.queue[event] = []
this.queue[event].push(fn)
}
once(event, fn) { //监听事件,只能触发一次
if (!this.onceQueue[event]) {
this.onceQueue[event] = {
fns: [],
hasFired: false
}
}
this.onceQueue[event].fns.push(fn)
}
fire() { //触发指定的事件
const event = [].shift.call(arguments), //取得事件名称
fns = this.queue[event], //取得该事件里所有的回调函数(可以触发多次的事件)
onceFns = this.onceQueue[event] //取得该事件里所有的回调函数(只能触发一次的事件)
if (fns && fns.length != 0) {
for (let item of fns) {
item.apply(this, arguments)
}
}
if (onceFns && !onceFns.hasFired) {
for (let item of onceFns.fns) {
item.apply(this, arguments)
}
this.onceQueue[event].hasFired = true
}
}
off(event, fn = null) { //可移除特定事件里的某个回调函数或者所有回调函数
const fns = this.queue[event]
if (!fns || fns.length == 0) return
if (fn) { //移除该事件特定的回调
this.queue[event] = fns.filter(item => {
return item !== fn
})
} else { //移除该事件所有的回调
this.queue[event] = []
}
}
}
观察者模式之ES6实现(二)的更多相关文章
- React和ES6(二)ES6的类和ES7的property initializer
React与ES6系列: React与ES6(一)开篇介绍 React和ES6(二)ES6的类和ES7的property initializer React与ES6(三)ES6类和方法绑定 React ...
- ES6入门(二)
目录 ES6入门(二) es6之解构赋值 数组的解构赋值 对象的解构赋值 字符串的解构赋值 数值和布尔值的解构赋值 函数参数的解构赋值 圆括号问题 ES6入门(二) es6之解构赋值 数组的解构赋值 ...
- 用vue.js学习es6(二):let和const使用
一.运行及关闭运行: 在上一节中我们用shift+右击在C:\vue\es6文件夹中打开命令行使用:npm run dev,打开了我们的vue界面. 如果要关闭则在命令行中按住ctrl+C则可以关闭. ...
- 委托、事件、Observer观察者模式的使用解析二
一.设计模式-Observer观察者模式 Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新.Observer模式是一种 ...
- 深入浅出ES6(二):迭代器和for-of循环
作者 Jason Orendorff github主页 https://github.com/jorendorff 我们如何遍历数组中的元素?20年前JavaScript刚萌生时,你可能这样实现数 ...
- JavaScript学习笔记 -- ES6学习(二) let 和const
ES6 中新增了两个命令: let 和const. let命令: let 用于声明变量,和var 类似,但是所声明的变量只在代码块中有效,不存在变量提升,有暂时性死区. 1.只在代码块中有效 和var ...
- ES6核心内容精讲--快速实践ES6(二)
Iterator和for...of 是什么: Iterator(遍历器)是专门用来控制如何遍历的对象,具有特殊的接口. 怎么用: Iterator(遍历器)对象带有next方法,每一次调用next方法 ...
- es6(二)
三 . 正则扩展: 1.构造函数的扩展 let regex = new Regex('xyz','i'); let regex2 = new Regex(/xyz/i);//test() 方法用于检测 ...
- 从零开始学 Web 之 ES6(二)ES5的一些扩展
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
随机推荐
- linux笔记_day05
1.bash以及特性 shell:外壳 GUI:KDE,Gnome,Xfce CLI:sh,csh,ksh,bash(born again shell) 进程:在每个进程看来,当前主机上只存在内核和当 ...
- D3开发中的资料整理
D3开发台阶比较高,需要对html,css,js非常熟练,还要对SVG非常熟悉,SVG不会就不要开发D3了,下面给大家推荐一本资料,为大家未来的开发提供便利. 这个框架产品不支持ie8,是这个产品的特 ...
- CentOS6.5运行yum报错:No module named yum
公司测试机环境不知道给我卸了什么包,导致yum运行报错状况: 报错情况: There was a problem importing one of the Python modulesrequired ...
- 数据库的连接使用——使用ADO.NET连接数据库
一.ADO.NET简介 ADO.NET是由很多类组成的一个类库,这些类库提供了很多对象,用来完成数据的连接.查询.插入.更新和删除等操作.其中主要包括以下对象: 1.Connection对象:用来连接 ...
- 自动化运维之cobbler安装centos7.3
自动化运维之cobbler安装centos7.3 一.cobbler简介和服务 Cobbler是一款自动化操作系统安装的实现,与PXE安装系统的区别就是可以同时部署多个版本的系统,而PXE只能选择一种 ...
- zabbix3.0使用ss命令对tcp连接数和状态的监控性能优化
zabbix3.0对tcp连接数及状态的监控优化 之前对tcp的监控采用netstat命令,发现在服务器繁忙的时候效果不理想,这个命令占用大量的cpu有时候高达90%以上,可能会导致业务的不稳定,所以 ...
- python语法小应用---列表和元组
声明:本文章为参考总结CSDN上知识点所获,只是用来总结自己学习而用,如有侵权,会删除! 列表(list): 列表就像一个线性容器,但是比C++的 lis t扩展多得多 列表里的元素可以是相同类型,也 ...
- 使用 CSS overscroll-behavior 控制滚动行为:自定义下拉刷新和溢出效果
CSS 的新属性 overscroll-behavior 允许开发者覆盖默认的浏览器滚动行为,一般用在滚动到顶部或者底部. 背景 滚动边界和滚动链接(boundary & chaining) ...
- 解决LoggerFactory is not a Logback LoggerContext but Logback is on the classpath
因为引用了log4j2同时还引用了logback
- cf797c 栈,字符串
还以为能用单调栈做出来,,想了老半天,最后发现模拟一下很好做的 按顺序把字符压栈即可 #include<bits/stdc++.h> using namespace std; #defin ...