JavaScript之观察者模式

2023-09-20 17:32:20

本文作者为 360 奇舞团前端开发工程师

概述

在日常开发中,开发人员经常使用设计模式来解决软件设计中的问题。其中,观察者模式是一种常用的模式,它可以帮助开发人员更好地处理对象之间的通信。在 JavaScript 中,观察者模式的应用非常广泛,可以用于实现事件处理、数据绑定等功能。本文将介绍观察者模式的基本概念和实现方式。

什么是观察者模式?

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象(observer)同时监听某一个主题对象(subject)。当主题对象发生变化时,它会自动通知所有的观察者对象,使它们能够及时更新自己的状态。

观察者模式的优点在于它可以实现对象之间的松耦合,使得 Subject 和 Observer 可以独立地变化,而不会相互影响。它还可以提高代码的复用性和可维护性,使得代码更加清晰和易于理解。

事件观察者

该模式的视图如下所示:

EventObserver
│ 
├── subscribe: 添加新的可观察事件
│ 
├── unsubscribe: 移除可观察事件
|
└── broadcast: 执行带有绑定数据的所有事件

首先要执行初始化EventObserver操作:

class EventObserver {
  constructor() {
    this.observers = [];
  }
}

从观察到的事件的空列表开始,并对每个新实例执行此操作。

订阅方法

要添加新事件,请执行以下操作:

subscribe(fn) {
  this.observers.push(fn);
}

获取观察到的事件列表并将新项目推送到数组中,事件列表是回调函数列表。

要测试这个方法,请执行以下操作:

const fn = () => {};

observer.subscribe(fn);

// Assert
assert.strictEqual(observer.observers.length, 1);

取消订阅方法

要删除事件,请执行以下操作:

unsubscribe(fn) {
  this.observers = this.observers.filter((subscriber) => subscriber !== fn);
}

从列表中过滤掉与回调函数匹配的内容。如果没有匹配,回调将保留在列表中,过滤器返回一个新列表并重新分配观察者列表。

要测试这个方法,请执行以下操作:

const observer = new EventObserver();
const fn = () => {};

observer.subscribe(fn);

observer.unsubscribe(fn);

// Assert
assert.strictEqual(observer.observers.length, 0);

回调必须与列表中的相同函数匹配,如果存在匹配项,取消订阅方法会将其从列表中删除。

广播法

要调用所有事件,请执行以下操作:

broadcast(data) {
  this.observers.forEach((subscriber) => subscriber(data));
}

这会遍历观察到的事件列表并执行所有回调。这样,你就可以获得与订阅事件必要的一对多关系,传入data是回调数据绑定的参数。

要测试这个方法,请执行以下操作:

const observer = new EventObserver();

let subscriberHasBeenCalled = false;
const fn = (data) => subscriberHasBeenCalled = data;

observer.subscribe(fn);

observer.broadcast(true);

// Assert
assert(subscriberHasBeenCalled);

使用 let 而不是 const 这样我们就可以更改变量的值,这使得变量可变,然后允许我在回调内部重新分配它的值。let 在代码中会向其他程序员发送一个信号,表明该变量在某个时刻正在发生变化,这样就增加了 JavaScript 代码的可读性和清晰度。

好了,我们已经学会了一个简单的观者模式在 javaScript 中的实现。

总结

这篇主要简单介绍了观察者模式和其简单的实现,设计模式还有很多种,例如:单例模式、策略模式、工厂模式等,我们的核心目的是要学习其思想,而不是死记硬背每一种模式的实现方式。只有理解了设计模式的思想,才能在各种业务场景中灵活地应用它们。

参考链接

https://www.digitalocean.com/community/tutorial-series/javascript-design-patterns

https://developer.mozilla.org/zh-CN/docs/learn/JavaScript https://zhuanlan.zhihu.com/p/77275289

- END -

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

5595bc0d25fbd65096e211041be78d7e.png

更多推荐

为何学linux及用处

为何学linux及用处目前企业使用的操作系统无非就是国产类的,windows和linux类。我们要提升自己的技能,需要学习这两款。我记得在大学时期,学习过windows以及linux,但当时觉得又不常用,就学的模棱两可。毕业之后,你会发现,其实这两种操作系统是很主流的。为什么学?下面就是一些工作中遇到的例子分享一下。我

golang 结合 cobra 使用 chatgpt qdrant 实现 ai知识库 cli

golang结合cobra使用chatgptqdrant实现ai知识库cli流程将数据集通过openaiembedding得到向量+组装payload,存入qdrant用户进行问题搜索,通过openaiembedding得到向量,从qdrant中搜索相似度大于0.8的数据从qdrant中取出数据得到参考答案将问题标题+

js兼容性的汇总

js兼容问题大多是在ie浏览器低版本以及ie浏览器和不同普通浏览器的差异事件对象document.onclick=function(ev){//谷歌火狐的写法,IE9以上支持,往下不支持;vare=ev;console.log(e);}document.onclick=function(){//谷歌和IE支持,火狐不支

css3动画基础详解(@keyframes和animation)

动画是使元素从一种样式逐渐变化为另外一种效果,CSS3动画的生成,主要依赖@keyframes定义动画,animation执行动画。@keyframes通过@keyframes规则创建动画。@keyframeskeyframes-name{keyframes-selector{css-styles;}}keyframe

【数据结构】哈希表(详)

文章目录前言正文一、基本概念二、基本原理1.哈希函数1.1直接定址法(常用)1.2除留余数法(常用)1.3平方取中法(了解)1.4折叠法(了解)1.5随机数法(了解)1.6数学分析法(了解)2.哈希冲突2.1平均查找长度2.2负载因子2.3闭散列(开放定制法)2.1.1线性探测2.1.2二次探测2.1.3二重哈希2.4

MySQL 8.0 OCP (1Z0-908) 考点精析-架构考点5:数据字典(Data Dictionary)

文章目录MySQL8.0OCP(1Z0-908)考点精析-架构考点5:数据字典(DataDictionary)File-basedMetadataStorage(基于文件的元数据存储)TransactionalDataDictionary(事务数据字典)SerializedDictionaryInformation(S

相机One Shot标定

1原理说明原理部分网上其他文章[1][2]也已经说的比较明白了,这里不再赘述。2总体流程参考论文作者开源的Matlab代码[3]和github上的C++代码[4]进行说明(不得不说还是Matlab代码更优雅)论文方法总体分两部,第一部是在画面中找到所有的类棋盘格角点,第二步是角点的基础上构建出棋盘格形状。3模块说明3.

【Verilog 教程】3.1 Verilog 连续赋值

关键词:assign,全加器连续赋值语句是Verilog数据流建模的基本语句,用于对wire型变量进行赋值。:格式如下assignLHS_target=RHS_expression;LHS(lefthandside)指赋值操作的左侧,RHS(righthandside)指赋值操作的右侧。assign为关键词,任何已经声

Redis面试二“缓存击穿是什么”

条件缓存击穿是应为Redis某个缓存数据设置了过期时间,而刚好有大并发数据请求这个数据,导致DB有大量请求,引发DB崩溃。第一种方法就是设置互称锁当缓存失效时不立即删除缓存而是用setnx设置一个互斥锁,当操作完成后在loaddb,并回设缓存,否则重试get缓存方法,这样就减少了直接大量访问DB的请求。实现@Servi

Java高级-动态代理

动态代理1.介绍2.案例1.介绍publicinterfaceStar{Stringsing(Stringname);voiddance();}publicclassBigStarimplementsStar{privateStringname;publicBigStar(Stringname){this.name=n

关于ClickHouse的SQL操作

目录clickhouse和mysql的比较5.1create5.2Insert1.标准INSERT2.从表到表的插入5.3Update和Delete1.删除操作2.修改操作clickhouse和mysql的比较共同点:都是关系型数据库,支持SQL查询语言;支持事务处理,具备ACID特性(原子性、一致性、隔离性、持久性)

热文推荐