观察者模式之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 ...
随机推荐
- Django开发笔记二
Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.xadmin添加主题.修改标题页脚和收起左侧菜单 # ...
- 【逆向工具】逆向工具101editor使用-游戏快速通关
[渡者游戏简介] 船夫小江将运送客人的,羊.狐狸.草等物品过河,如果留下动物被其它种类吃掉任务就失败了.你需要帮助他做出正确的顺序选择.Ferryman是一款根据经典谜题改编的解谜游戏. 一.查看文件 ...
- Vistual Studio Community 2017 账号的许可证过期,公安网激活方法
方法: 1.外网电脑打开Vistual Studio Community2017 2.在许可证过期弹窗中登陆账号即可自动下载许可证完成激活 许可证下载路径(C:\用户\user\Ap ...
- Eclipse通过jdbc连接sqlserver2008数据库的两种方式
数据库登录身份验证方式有两种 其中服务器名称即为安装SQLServer2008的电脑,充当数据库服务器,在笔者这里就是自己的电脑名称. 身份验证方式有两种:windows身份验证和SQLSer ...
- SPLAY,LCT学习笔记(五)
这一篇重点探讨LCT的应用 例:bzoj 2631 tree2(国家集训队) LCT模板操作之一,利用SPLAY可以进行区间操作这一性质对维护懒惰标记,注意标记下传顺序和如何下传 #include & ...
- Zookeeper单机安装部署与配置(二)
在上篇博客中简单介绍了Zookeeper的特点和应用场景,详情可参考:<Zookeeper简介(一)>,那么这篇博客我们介绍一下关于Zookeeper的单机模式安装步骤与配置. 环境准备 ...
- 用函数打印Hello js
<script> function sayHello() { document.write("Hello js!"); } sayHello(); </scrip ...
- oracle中计算某月的天数
select add_months(to_date('201202', 'YYYYMM'),1)-to_date('201202', 'YYYYMM') from dual
- Ext.js入门(二)
ExtJs OOP基础 一:ExtJs中的面向对象 1.ExtJs中命名空间的定义 Ext中的命名空间类似于C#中的namespace和java中的包,用来对工程中的类进行更好的 ...
- Android Studio之导出JavaDoc出现编码GBK的不可映射字符
使用Android Studio导出JavaDoc时,如果在注释中添加了中文,生成时的时候会出现错误: 编码GBK的不可映射字符. 解决的办法是在Other command line argument ...