javascript设计模式有哪些_如何实现单例或观察者模式?

发布时间 - 2025-12-27 00:00:00    点击率:
JavaScript常用设计模式包括单例、观察者、工厂、策略等,其中单例确保全局唯一实例,常通过静态属性或模块导出实现;观察者模式实现一对多依赖通知,发布-订阅则进一步解耦为事件中心通信。

JavaScript 中常用的设计模式有单例模式、观察者模式、工厂模式、策略模式、代理模式、装饰器模式、发布-订阅模式、状态模式、命令模式等。其中单例和观察者(或其变体“发布-订阅”)在实际开发中出现频率高,实现也相对轻量。

单例模式:确保一个类只有一个实例

核心是控制实例的创建时机与访问方式,避免重复初始化。JS 中没有类的严格封装,常用闭包或静态属性 + 条件判断来实现。

常见写法(ES6 Class + 静态实例):

class Logger {
  constructor() {
    if (Logger.instance) {
      return Logger.instance;
    }
    this.logs = [];
    Logger.instance = this;
  }

  log(msg) {
    this.logs.push(`[${Date.now()}] ${msg}`);
  }
}

// 使用
const a = new Logger();
const b = new Logger();
console.log(a === b); // true

更稳妥的方式是用私有静态变量(ES2025+)或模块级闭包隐藏实例:

  • 模块导出一个已创建的对象,天然单例(推荐,简单可靠)
  • Symbol 或 WeakMap 存储私有实例,防止外部篡改构造函数
  • 注意:new 操作符配合 return 对象会跳过原型链,需手动绑定或改用工厂函数

观察者模式:对象间一对多依赖,被观察者变化时通知所有观察者

典型结构包含 Subject(目标)和 Observer(观察者)。JS 中常简化为:Subject 管理回调队列,提供 subscribe / unsubscribe / notify 方法。

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

  subscribe(observer) {
    if (typeof observer === 'function') {
      this.observers.push(observer);
    }
  }

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

  notify(data) {
    this.observers.forEach(observer => observer(data));
  }
}

// 使用
const subject = new Subject();
subject.subscribe(msg => console.log('A:', msg));
subject.subscribe(msg => console.log('B:', msg));
subject.notify('Hello'); // A: Hello, B: Hello

实际项目中,更常见的是“发布-订阅”(Pub/Sub)——解耦更彻底,通过事件中心通信,不直接持有观察者引用:

  • 用对象存储事件名 → 回调数组映射(如 { click: [fn1, fn2], load: [fn3] }
  • 支持通配符、once、优先级等可扩展能力(如 EventEmitter)
  • Vue 的 $on/$emit、Node.js 的 EventEmitter 都是该思想的体现

什么时候选哪种?

单例适合全局唯一状态管理(如配置中心、日志器、缓存实例);观察者适合松耦合通信(如 UI 更新、跨组件通知);发布-订阅更适合大型系统中模块间解耦。

基本上就这些。不复杂但容易忽略细节,比如单例的构造拦截是否健壮、观察者是否及时取消订阅防内存泄漏。


# vue  # javascript  # es6  # java  # js  # node.js  # node 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: IOS倒计时设置UIButton标题title的抖动问题  网站制作价目表怎么做,珍爱网婚介费用多少?  详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南  如何用景安虚拟主机手机版绑定域名建站?  网站建设整体流程解析,建站其实很容易!  bootstrap日历插件datetimepicker使用方法  在Oracle关闭情况下如何修改spfile的参数  Laravel DB事务怎么使用_Laravel数据库事务回滚操作  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  如何在IIS7中新建站点?详细步骤解析  Laravel如何生成API文档?(Swagger/OpenAPI教程)  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  详解jQuery中的事件  Laravel怎么调用外部API_Laravel Http Client客户端使用  如何快速搭建虚拟主机网站?新手必看指南  如何用好域名打造高点击率的自主建站?  如何自定义safari浏览器工具栏?个性化设置safari浏览器界面教程【技巧】  Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全  如何用腾讯建站主机快速创建免费网站?  浏览器如何快速切换搜索引擎_在地址栏使用不同搜索引擎【搜索】  javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】  百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  googleplay官方入口在哪里_Google Play官方商店快速入口指南  Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】  DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解  如何在香港服务器上快速搭建免备案网站?  JS实现鼠标移上去显示图片或微信二维码  Laravel如何为API生成Swagger或OpenAPI文档  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  如何用AI帮你把自己的生活经历写成一个有趣的故事?  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  Laravel如何使用withoutEvents方法临时禁用模型事件  Laravel事件和监听器如何实现_Laravel Events & Listeners解耦应用的实战教程  HTML 中如何正确使用模板变量为元素的 name 属性赋值  Laravel如何使用查询构建器?(Query Builder高级用法)  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  香港服务器网站推广:SEO优化与外贸独立站搭建策略  如何快速打造个性化非模板自助建站?  微信公众帐号开发教程之图文消息全攻略  标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南  Laravel storage目录权限问题_Laravel文件写入权限设置  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法  Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑  Laravel怎么使用Intervention Image库处理图片上传和缩放  如何快速生成橙子建站落地页链接?