javaScript设计模式是解决特定问题的对象组织方式和协作关系,决定代码可维护性、可测试性与协作效率;单例确保全局唯一实例,工厂封装对象创建逻辑,观察者实现松耦合通信。

javascript 设计模式不是语法糖,也不是框架专属功能,而是一套被反复验证过的、解决特定问题的**对象组织方式和协作关系**。它不改变代码能否运行,但直接决定你写出来的模块好不好改、好不好测、多人协作时别人能不能一眼看懂。
单例模式:为什么 new DatabaseConnection() 不能随便写
当你需要全局唯一资源(比如日志器、配置管理器、websocket 连接),每次 new 都会创建新实例,轻则浪费内存,重则导致状态错乱或连接泄漏。
- 错误做法:
const logger1 = new Logger(); const logger2 = new Logger();—— 两个独立实例,日志可能写到不同文件或丢失上下文 - 正确做法:用私有静态属性 + 构造拦截,确保
Logger.getInstance()总返回同一个对象 - 注意惰性初始化:实例只在第一次调用
getInstance()时创建,避免页面加载就占资源 - es6 class 实现时别忘了在构造函数里检查
if (Logger.instance) return Logger.instance,否则new仍可绕过控制
工厂模式:当 if/else 创建对象开始蔓延时就得收手
你是不是写过这样的代码:if (role === 'admin') { return new AdminUser(); } else if (role === 'vip') { ... }?这种逻辑一旦散落在多个文件里,改一个角色就要全局搜、逐个修。
- 工厂本质是把“怎么造”藏起来,暴露统一接口:
UserFactory.create('admin') - 适合场景:API 返回不同类型数据需映射为不同类;组件按权限动态加载;表单校验规则按字段类型分发
- 进阶技巧:配合
import()动态导入,让工厂只加载当前需要的模块,避免打包体积膨胀 - 别把工厂写成巨型 switch:超过 4–5 种类型时,考虑用注册表模式(
factory.register('admin', AdminUser))解耦
观察者模式:vue 的 $emit 和 react 的自定义 Hook 背后都是它
它解决的是「谁变了,谁通知,谁响应」的问题。不是所有通信都要用 Redux;两个组件之间状态联动,观察者往往更轻、更直接。
- 核心结构只有三样:
subscribe()订阅、notify()发布、observers存回调 - 常见坑:忘记取消订阅 → 内存泄漏(尤其在组件卸载时);用箭头函数订阅导致
this指向错乱 - 真实场景:表单联动(选城市 → 刷新区域下拉)、WebSocket 心跳失败后触发重连广播、性能监控上报完成事件
- 和发布-订阅的区别不大,但工程中建议用
EventBus类封装,避免直接操作document或window自定义事件,方便单元测试
真正难的不是写出一个能跑的单例或工厂,而是判断「这里到底该用哪种模式」——比如该用策略模式处理支付方式(支付宝/微信/银联),还是该用状态模式处理订单生命周期(待付款→已发货→已完成)。模式本身没高下,匹配业务脉络才关键。