javascript设计模式有哪些_如何实现单例模式

单例模式确保一个类只有一个实例并提供全局访问点,核心是无论调用多少次都返回同一实例,需通过私有静态变量、私有化构造函数和统一获取方法(如getInstance)实现,支持懒加载或立即创建。

JavaScript 中常用的设计模式包括单例模式、工厂模式、观察者模式(发布-订阅)、策略模式、代理模式、装饰器模式、适配器模式、命令模式、状态模式等。其中,单例模式用于确保一个类只有一个实例,并提供全局访问点。

单例模式的核心要点

单例不是“只能创建一个对象”,而是“无论调用多少次,始终返回同一个实例”。关键在于控制实例的创建时机与唯一性,避免重复初始化。

  • 需要一个私有静态变量保存唯一实例
  • 构造函数应防止外部直接 new(常通过闭包或 Symbol 隐藏)
  • 提供统一的获取实例方法(如 getInstance)
  • 支持懒加载(首次调用才创建)或立即创建

基础单例实现(闭包 + 懒加载)

利用立即执行函数(IIFE)封装私有变量,返回带 getInstance 的对象:

const Singleton = (function() {
  let instance = null;

  function createInstance() {
    return {
      data: Math.random(),
      getName() { return 'Singleton Instance'; }
    };
  }

  return {
    getInstance() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// 使用
const a = Singleton.getInstance();
const b = Singleton.getInstance();
console.log(a === b); // true

ES6 Class 单例写法(推荐)

用 static 属性保存实例,constructor 私有化(通过私有字段或检查机制):

class Logger {
  static #instance = null;

  constructor() {
    if (Logger.#instance) {
      throw new Error('Logger is a singleton. Use Logger.getInstance()');
    }
    this.logs = [];
  }

  static getInstance() {
    if (!Logger.#instance) {
      Logger.#instance = new Logger();
    }
    return Logger.#instance;
  }

  log(msg) {
    this.logs.push(msg);
  }
}

// 使用
const logger1 = Logger.getInstance();
const logger2 = Logger.getInstance();
console.log(logger1 === logger2); // true

带参数的单例(可配置但仅初始化一次)

如果需传参初始化(如配置项),应在首次调用 getInstance 时接收,后续忽略:

class Database {
  static #instance = null;
  static #config = null;

  constructor(config) {
    if (Database.#instance) {
      throw new Error('Database is singleton');
    }
    this.config = config || Database.#config;
  }

  static getInstance(config) {
    if (!Database.#instance) {
      Database.#config = config;
      Database.#instance = new Database(config);
    }
    return Database.#instance;
  }
}

注意:这种写法下,config 只在第一次有效;若需动态重置,应额外提供 reset 方法,但会破坏“单例”的语义,慎用。