【Web前端】JavaScript设计模式全解析

JavaScript 设计模式是在软件开发中针对常见问题的可复用解决方案。由于 JavaScript 是动态、原型继承、支持函数式与面向对象的多范式语言,许多传统设计模式在 JavaScript 中既有经典实现,也有更简洁的现代实现。


1. 设计模式分类

通常参考 GoF(Gang of Four)的 23 种设计模式,分为三大类:

1)创建型:对象创建机制

2)结构型:对象组合与类之间的关系

3)行为型:对象之间的职责分配与通信

在 JavaScript 中,由于函数是一等公民、闭包、原型链等特性,有些模式实现更为灵活。


2. 创建型模式

2.1 单例模式(Singleton)

确保一个类只有一个实例,并提供全局访问点。

实现 :利用闭包或 Symbol 控制实例。

复制代码
const Singleton = (function() {
  let instance;
  function createInstance() {
    return { data: 'single instance' };
  }
  return {
    getInstance: function() {
      if (!instance) instance = createInstance();
      return instance;
    }
  };
})();

// ES6 类方式
class SingletonClass {
  constructor() {
    if (!SingletonClass.instance) {
      SingletonClass.instance = this;
    }
    return SingletonClass.instance;
  }
}

2.2 工厂模式(Factory Method)

将对象的创建与使用分离,通过一个函数返回不同类型的对象。

复制代码
function Car(brand) {
  this.brand = brand;
}
function Bike(brand) {
  this.brand = brand;
}
function vehicleFactory(type, brand) {
  switch(type) {
    case 'car': return new Car(brand);
    case 'bike': return new Bike(brand);
    default: throw new Error('Unknown type');
  }
}

抽象工厂:一组工厂方法,创建一系列相关对象。

2.3 建造者模式(Builder)

将复杂对象的构建过程分步完成,与表示分离。

复制代码
class Burger {
  constructor(builder) {
    this.size = builder.size;
    this.cheese = builder.cheese;
  }
  static Builder = class {
    constructor(size) { this.size = size; }
    addCheese() { this.cheese = true; return this; }
    build() { return new Burger(this); }
  }
}
const myBurger = new Burger.Builder('large').addCheese().build();

2.4 原型模式(Prototype)

通过克隆已有对象来创建新对象,利用 JavaScript 的原型链。

复制代码
const carPrototype = {
  init(brand) { this.brand = brand; return this; },
  drive() { console.log(`Driving ${this.brand}`); }
};
const myCar = Object.create(carPrototype).init('Tesla');
// 或使用 ES6 类继承自动实现原型模式

3. 结构型模式

3.1 适配器模式(Adapter)

将一个类的接口转换成客户期望的另一个接口,解决接口不兼容。

复制代码
class OldAPI {
  request() { return 'old data'; }
}
class NewAPI {
  fetch() { return 'new data'; }
}
// 适配器
class Adapter {
  constructor(newAPI) { this.newAPI = newAPI; }
  request() { return this.newAPI.fetch(); }
}

3.2 装饰器模式(Decorator)

动态给对象添加额外职责,不修改原有结构。JavaScript 中常用高阶函数或类装饰器(提案阶段)。

复制代码
function withLogging(fn) {
  return function(...args) {
    console.log(`Calling ${fn.name}`);
    return fn(...args);
  };
}
const add = (a,b) => a+b;
const loggedAdd = withLogging(add);

3.3 代理模式(Proxy)

为另一个对象提供替身或占位符,控制对其的访问。ES6 原生 Proxy 可直接实现。

复制代码
const target = { message: 'hello' };
const handler = {
  get(obj, prop) {
    if (prop === 'message') return obj[prop].toUpperCase();
    return obj[prop];
  }
};
const proxy = new Proxy(target, handler);
console.log(proxy.message); // HELLO

3.4 外观模式(Facade)

为复杂子系统提供统一的简化接口。

复制代码
class CPU { freeze() { /*...*/ } jump() { /*...*/ } execute() { /*...*/ } }
class Memory { load() { /*...*/ } }
class ComputerFacade {
  constructor() { this.cpu = new CPU(); this.memory = new Memory(); }
  start() {
    this.cpu.freeze();
    this.memory.load();
    this.cpu.jump();
    this.cpu.execute();
  }
}

3.5 组合模式(Composite)

将对象组合成树形结构以表示"部分-整体"层次,使单个对象和组合对象有一致接口。

复制代码
class Graphic { draw() {} }
class Circle extends Graphic { draw() { console.log('draw circle'); } }
class CompositeGraphic extends Graphic {
  constructor() { super(); this.graphics = []; }
  add(g) { this.graphics.push(g); }
  draw() { this.graphics.forEach(g => g.draw()); }
}

4. 行为型模式

4.1 观察者模式(Observer)与发布订阅(Publish/Subscribe)

定义对象间的一对多依赖,当主题变化时通知所有观察者。发布订阅通过中间代理进一步解耦。

观察者(Subject 直接持有 Observer 列表):

复制代码
class Subject {
  constructor() { this.observers = []; }
  attach(observer) { this.observers.push(observer); }
  notify(data) { this.observers.forEach(obs => obs.update(data)); }
}
class Observer {
  update(data) { console.log('received', data); }
}

发布订阅(事件中心):

复制代码
const EventBus = {
  events: {},
  subscribe(event, callback) {
    if (!this.events[event]) this.events[event] = [];
    this.events[event].push(callback);
  },
  publish(event, data) {
    if (this.events[event]) this.events[event].forEach(cb => cb(data));
  }
};

4.2 策略模式(Strategy)

定义一系列算法,使其可以互相替换,算法的变化独立于使用算法的客户。

复制代码
const strategies = {
  plus: (a,b) => a+b,
  minus: (a,b) => a-b,
};
function execute(strategy, a, b) {
  return strategies[strategy](a,b);
}
console.log(execute('plus', 5, 3)); // 8

4.3 命令模式(Command)

将请求封装为对象,从而支持参数化、队列、日志、撤销等。

复制代码
class Light { turnOn() { console.log('light on'); } }
class TurnOnCommand {
  constructor(light) { this.light = light; }
  execute() { this.light.turnOn(); }
}
class RemoteControl {
  setCommand(cmd) { this.command = cmd; }
  pressButton() { this.command.execute(); }
}

4.4 迭代器模式(Iterator)

提供一种方法顺序访问聚合对象中的元素,而不暴露其内部表示。JavaScript 内置 Symbol.iterator 支持。

复制代码
const myIterable = {
  items: [1,2,3],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => ({
        value: this.items[index++],
        done: index > this.items.length
      })
    };
  }
};
for (let val of myIterable) console.log(val);

4.5 中介者模式(Mediator)

用一个中介对象封装一系列对象之间的交互,使对象不必显式相互引用。

复制代码
class Mediator {
  constructor() { this.colleagues = []; }
  register(c) { this.colleagues.push(c); c.mediator = this; }
  send(sender, msg) {
    this.colleagues.forEach(c => { if (c !== sender) c.receive(msg); });
  }
}
class Colleague {
  constructor(name) { this.name = name; }
  send(msg) { this.mediator.send(this, msg); }
  receive(msg) { console.log(`${this.name} got ${msg}`); }
}

4.6 状态模式(State)

允许对象在其内部状态改变时改变其行为,看起来像是修改了它的类。

复制代码
class Context {
  constructor() { this.state = new StateA(); }
  setState(state) { this.state = state; }
  request() { this.state.handle(this); }
}
class StateA { handle(ctx) { console.log('state A'); ctx.setState(new StateB()); } }
class StateB { handle(ctx) { console.log('state B'); ctx.setState(new StateA()); } }

4.7 模板方法模式(Template Method)

在父类中定义算法的骨架,让子类实现具体步骤。

复制代码
class Beverage {
  boilWater() { console.log('boil water'); }
  brew() { throw new Error('must override'); }
  pourInCup() { console.log('pour in cup'); }
  addCondiments() { throw new Error('must override'); }
  prepare() {
    this.boilWater();
    this.brew();
    this.pourInCup();
    this.addCondiments();
  }
}
class Coffee extends Beverage {
  brew() { console.log('brew coffee'); }
  addCondiments() { console.log('add sugar'); }
}

5. JavaScript 特有的设计模式

5.1 模块模式(Module Pattern)

利用立即执行函数表达式(IIFE)或 ES6 模块实现私有变量和封装。

复制代码
// IIFE 模块
const module = (function() {
  let privateVar = 0;
  function privateMethod() {}
  return {
    publicMethod() { privateVar++; }
  };
})();

// ES6 模块 (文件)
// export const publicVar = 1;
// export function publicMethod() {}

5.2 混入模式(Mixin)

将多个对象的属性和方法混合到一个对象,实现多重继承的效果。

复制代码
const mixin = {
  sayHi() { console.log(`Hi, I'm ${this.name}`); }
};
class Person {
  constructor(name) { this.name = name; }
}
Object.assign(Person.prototype, mixin);

5.3 高阶组件模式(React 等框架中常见)

在 React 中,通过函数接收组件并返回增强后的新组件,属于装饰器模式的一种应用。


6. 现代 JavaScript 对设计模式的影响

1)ES6 类 :简化了构造函数、继承和 super 调用,使传统面向对象模式(如工厂、建造者)更易读。

2)Proxy 与 Reflect:原生支持代理模式,可实现元编程、数据劫持等。

3)模块系统 :原生模块(import/export)取代了以往的 IIFE 模块模式。

4)箭头函数:简化回调,在策略模式、观察者模式中更简洁。

5)Symbol :可用于定义私有属性(通过 Symbol.for)或防止属性名冲突。

6)Decorator 提案:未来可能提供标准的装饰器语法,简化装饰器模式。


7. 总结

设计模式是解决特定问题的经验总结,但使用时应注意:

1)不要过度设计:在简单场景下直接实现可能比套用模式更合适。

2)结合语言特性:JavaScript 的动态性允许用更简单的方式实现很多模式(如函数代替策略类)。

3)保持代码可读性:模式名称可作为代码注释,帮助团队理解意图。

深入理解设计模式,能帮助写出更健壮、可维护的 JavaScript 代码。在实际项目中,常用模式(如单例、观察者、策略、模块)几乎无处不在,值得熟练掌握。

相关推荐
小码哥_常2 小时前
从SharedPreferences到DataStore:Android存储进化之路
前端
老黑2 小时前
开源工具 AIDA:给 AI 辅助开发加一个数据采集层,让 AI 从错误中自动学习(Glama 3A 认证)
前端·react.js·ai·nodejs·cursor·vibe coding·claude code
薛先生_0992 小时前
js学习语法第一天
开发语言·javascript·学习
jessecyj2 小时前
Spring boot整合quartz方法
java·前端·spring boot
苦瓜小生2 小时前
【前端】|【js手撕】经典高频面试题:手写实现function.call、apply、bind
java·前端·javascript
天若有情6732 小时前
前端HTML精讲03:页面性能优化+懒加载,搞定首屏加速
前端·性能优化·html
踩着两条虫2 小时前
AI驱动的Vue3应用开发平台深入探究(十):物料系统之内置组件库
android·前端·vue.js·人工智能·低代码·系统架构·rxjava
和沐阳学逆向3 小时前
我现在怎么用 CC Switch 管中转站,顺手拿 Codex 举个例子
开发语言·javascript·ecmascript
swipe3 小时前
AI 应用里的 Memory,不是“保存聊天记录”,而是管理上下文预算
前端·llm·agent