用观察者模式编写一个可被其他对象拓展复用自定义事件系统

观察者模式

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知

什么是观察者模式?

发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。在 JavaScript 开发中,我们一般用事件模型来替代传统的发布—订阅模式。

举个栗子:

卖水果的张老板和王老板都要进一批香蕉,他们的水果都是在一个叫钱多多(下面统称为钱老板)的水果批发商那里进的。当张老板和王老板到钱老板那里进水果的时候,钱老板告诉张老板和王老板,香蕉还没有到货,得过几天才到货。无奈之下,张老板和王老板都把他们的电话号码留在了钱老板那里,嘱咐钱老板,香蕉到货后,第一时间通知他们。

上面钱老板就扮演了发布者的角色,张老板和王老板则扮演的是订阅者角色。在香蕉到货后,钱老板会主动给张老板和王老发消息,让两位老板来取香蕉。这样的好处就是:香蕉没到的这段时间,张老板和王老板可以做其他的事情,不用主动联系钱老板,只需等待钱老板的消息即可。也就是程序代码中的时间上解耦,对象间解耦。

自定义事件

其实观察者模式我们都曾使用过,就是我们熟悉的事件
但是内置的事件很多时候不能满足我们的要求
所以我们需要自定义事件


现在我们想实现这样的功能 定义一个事件对象,它有以下功能

  • 监听事件(订阅事件)
  • 触发事件(事件发布)
  • 移除事件(取消订阅事件)

当然我们不可能只订阅一个事件,可能会有很多
所以我们要针对不同的事件设置不同的”键”
这样我们储存事件的结构应该是这样的

EventList = {evtName1: [回调函数1,回调函数2,...],evtName2: [回调函数1,回调函数2,...],evtName3: [回调函数1,回调函数2,...],
}

代码如下

var createEventSys = function(){return {// 通过on接口监听事件eventName// 如果事件eventName被触发,则执行callback回调函数on: function (eventName, callback) {//如果Event对象没有handles属性,则给Event对象定义属性handles,初始值为{}//handles属性是用来存储事件和回调执行函数的(即存储订阅的事件和触发事件后执行的相应函数方法)if(!this.handles){this.handles={};}//如果handles中不存在事件eventName,则将事件存储在handles中,同时初始化该事件对应的回调逻辑函数集合if(!this.handles[eventName]){this.handles[eventName]=[];}//往handles中的eventName对应的回调逻辑函数集合push回调函数callbackthis.handles[eventName].push(callback);},// 触发事件 eventNameemit: function (eventName) {//如果事件eventName有订阅者,则依次执行事件eventName的订阅者相应的回调方法if(this.handles[arguments[0]]){for(var i=0;i<this.handles[arguments[0]].length;i  ){this.handles[arguments[0]][i](arguments[1]);}}},//移除事件 eventNameremove: function (eventName, fn) {//判断事件eventName是否存在fn这个观察者,如果有,则移除事件eventName的fn观察者if(this.handles[eventName]){for(var i=0; i<this.handles[eventName].length; i  ){if(this.handles[eventName][i] === fn){this.handles[eventName].splice(i,1);break;}}}}};
}
var Event = createEventSys();
Event.on('test', function (result) {console.log(result);
});
Event.on('test', function () {console.log('test');
});
Event.emit('test', 'hello world'); // 输出 'hello world' 和 'test'//对象person1和对象person2拓展复用自定义系统
var person1 = {};
var person2 = {};
Object.assign(person1, createEventSys());
Object.assign(person2, createEventSys());
person1.on('call1', function () {console.log('person1');
});
person2.on('call2', function () {console.log('person2');
});
person1.emit('call1'); // 输出 'person1'
person1.emit('call2'); // 没有输出
person2.emit('call1'); // 没有输出
person2.emit('call2'); // 输出 'person2'

如上面代码这样,我们用观察者模式就实现了一个基本完善的自定义事件系统。

总结

观察者模式有两个明显的优点

时间上解耦
对象间解耦

在前端开发中,很多地方都适合用观察者模式来做,在适当的地方善用观察者模式

希望这篇文章对大家有帮助,喜欢的话,请关注我,我会持续更新一些技术文章到我的掘金主页,谢谢大家支持!


更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

布局定位

布局与定位 摆放元素 1&#xff0c;使用流 流实际上就是浏览器在页面上摆放HTML元素所用的方法。浏览器从HTML文件最上面开始&#xff0c;从上到下沿着元素流逐个显示所遇到的各个元素。 每个块元素会按它在HTML标记中出现的顺序放置在页面上。每个新的块元素会带来一个换行。并…

T - Memory and Trident CodeForces - 712B( 注意:* ++ = 的优先级

题意&#xff1a;有四种命令&#xff1a;U代表上移一个单位&#xff0c;D代表下移一个单位&#xff0c;R代表右移一个单位&#xff0c;L代表左移一个单位。 现在给出一串命令&#xff0c;问怎样修改命令中的任意一条命令&#xff0c;使得命令结束后重新返回原点&#xff0c;并且…

python语言精通_Python语言基础从入门到精通

1、python关键字False await else import passNone break except in raiseTrue class finally is returnand continue for lambda tryas def from nonlocal whileassert del global not withasync elif if or yield2、命令行参数williamdeMBP-2:~ william$ python -c "imp…

休眠事实:了解刷新操作顺序很重要

Hibernate将开发人员的思维方式从思考SQL转变为思考对象状态转换。 根据Hibernate Docs&#xff0c;实体可能处于以下状态之一&#xff1a; new / transient&#xff1a;实体不与持久性上下文关联&#xff0c;因为它是数据库不知道的新创建的对象。 持久性&#xff1a;实体与…

[HNOI2012]排队

题目描述 某中学有 n 名男同学&#xff0c;m 名女同学和两名老师要排队参加体检。他们排成一条直线&#xff0c;并且任意两名女同学不能相邻&#xff0c;两名老师也不能相邻&#xff0c;那么一共有多少种排法呢&#xff1f;&#xff08;注意&#xff1a;任意两个人都是不同的&a…

声速的测量的实验原理和应用_声速的测定实验报告心得体会

测量声速的实验报告1。提出问题如何测出声音的速度?2。猜想与假设如果在一定距离内听到声音要多少时间?3。实验步骤步骤应该就是实施实验&#xff0c;第三是实验器材的话&#xff0c;就是要秒表。4。实施实验在一个山谷中&#xff0c;站在距离峭壁680M的地方大叫一声&#xf…

FreeNAS:创建 CIFS 共享(权限)

第一部分&#xff1a;新建账户与指定数据集权限 简单起见&#xff0c;本教程主要介绍带基本身份验证的 CIFS 共享&#xff0c;即只有输入正确的用户名和密码才可以访问共享目录。关于创建匿名共享、多用户权限管理以及域控制器相关内容&#xff0c;我们会另外发布教程专门介绍。…

使用序列化查找对象中的脏字段

假设您正在开发一个将对象自动保存到数据库中的框架。 您需要检测两次保存之间所做的更改&#xff0c;以便仅保存修改过的字段。 如何检测脏场。 最简单的方法是遍历原始数据和当前数据&#xff0c;并分别比较每个字段。 代码如下&#xff1a; public static void getDirtyFie…

js操作table中tr的顺序,实现上移下移一行的效果

总体思路是在table外部加个div&#xff0c;修改div的innerHtml实现改变tr顺序的效果 具体思路是 获取当前要移动tr行的rowIndex&#xff0c;在table中删除掉&#xff0c;然后循环table的rows&#xff0c;到了目标行再直接加进去&#xff0c;最后把整体的html赋值给div完成效果…

oracle日记账单据编号未生成_商管财务数据平台Oracle与共享未付池差异如何核对、解决?...

‍‍近期&#xff0c;总部新上线财务数据平台啦&#xff01;各个系统间的差异异常数据清晰可见&#xff0c;随时可查&#xff0c;今天就和小伙伴们一起分享一下Oracle与共享未付池差异如何核对、解决。首先&#xff0c;将Oracle与共享未付池差异数据导出。由于导出的数据包括本…

python (六)函数

一、函数的形成 需求1&#xff1a;来测试一下‘hello word’ 的长度 # 在没有函数的时候&#xff0c;我们可以用for循环实现 s1 "hello world" length 0 for i in s1:length length1 print(length) 再增加一个需求2&#xff1a;再来测试一下另外一个字符串的长度&…

Java方法中的参数太多,第4部分:重载

期望将过多的参数传递给Java方法的问题之一是&#xff0c;该方法的客户端很难确定它们是否以适当的顺序传递了适当的值。 在以前的文章中&#xff0c;我描述了如何使用自定义类型 &#xff0c; 参数对象和构建器来解决此问题。 解决此问题的另一种方法&#xff08;也是本文的主…

android paint 圆角 绘制_[BOT] 一种android中实现“圆角矩形”的方法

内容简介文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式&#xff0c;四个角可以分别指定为圆角。思路是利用“Xfermode Path”来进行Bitmap的裁剪。背景圆角矩形实现的方法应该很多&#xff0c;网上一大堆。很怀疑为啥安卓的控件不内置这样的属…

解决高度塌陷问题

所谓高度塌陷就是在文档流中&#xff0c;父元素的高度默认是被子元素撑开的&#xff0c;也就是子元素多高&#xff0c;父元素就多高。但是当为子元素设置浮动以后&#xff0c;子元素会完全脱离文档流&#xff0c;此时将会导致子元素无法撑起父元素的高度&#xff0c;导致父元素…

HDU2035 - 人见人爱A^B

求A^B的最后三位数表示的整数。 说明&#xff1a;A^B的含义是“A的B次方” Input 输入数据包含多个测试实例&#xff0c;每个实例占一行&#xff0c;由两个正整数A和B组成&#xff08;1<A,B<10000&#xff09;&#xff0c;如果A0, B0&#xff0c;则表示输入数据的结束&…

Cisco TrustSec(理解)

1、Cisco TrustSec的限制当指定了无效的设备ID时&#xff0c;受保护的访问凭据&#xff08;Protected access credential&#xff0c;PAC&#xff09;设置将失败并保持挂起状态。 即使在清除PAC并配置正确的设备ID和密码后&#xff0c;PAC仍然会失败。作为解决方法&#xff0c;…

Java 8仍然需要LINQ吗? 还是比LINQ更好?

长期以来&#xff0c; LINQ是.NET软件工程生态系统中发生的最好的事情之一。 通过在Visual Studio 2008中引入lambda表达式和monads &#xff0c;它使C&#xff03;语言比Java&#xff08;当时的版本6&#xff09;更先进&#xff0c;并且仍在讨论泛型类型擦除的优缺点。 这项成…

web前端(12)—— 页面布局2

本篇博文&#xff0c;主要就讲定位的问题&#xff0c;也就是页面布局里最重要的&#xff0c;本篇博文不出意外的话&#xff0c;也是css的最后一篇博文了 定位&#xff0c;position属性 定位有三种&#xff1a; 相对定位绝对定位固定定位 相对定位&#xff0c;position&#x…

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

题目链接 \(Description\) 给定一棵树。每次询问给定\(a\sim b,c\sim d\)两个下标区间&#xff0c;从这两个区间中各取一个点&#xff0c;使得这两个点距离最远。输出最远距离。\(n,q\leq10^5\)。 \(Solution\) 一个集合直径的两端点&#xff0c;在被划分为两个集合后一定是两个…

Web应用程序中的Spring JDBC入门

在上一篇文章中&#xff0c;我已经向您展示了如何设置基本的Spring 3 MVC Web应用程序 。 重复使用该项目设置作为模板&#xff0c;我将向您展示如何增强它以与JDBC一起使用。 有了它&#xff0c;您可以存储和检索数据库中的数据。 我们将通过Spring添加一个新的控制器和一个数…