如何复用参数相同的JS Class实例,避免重复执行构造函数?
解决方案:基于参数的实例复用(享元模式)
你需要的是**享元模式(Flyweight Pattern)**的实现,核心是根据传入的参数缓存已创建的实例,避免重复执行构造逻辑。下面提供两种优雅的实现方式:
方式一:改造构造函数,保留new语法
通过类的私有静态属性存储已缓存的实例,在构造函数中先检查缓存,存在则直接返回已有实例,不存在则创建新实例并缓存:
class MyClass { // 私有静态属性:存储已创建的实例,key为参数url static #instances = new Map(); constructor(url) { // 先检查缓存中是否存在对应url的实例 if (MyClass.#instances.has(url)) { return MyClass.#instances.get(url); } // 不存在则执行构造逻辑 this.url = url; console.log("Constructing MyClass with", url); // 将新实例存入缓存 MyClass.#instances.set(url, this); } } // 测试代码 new MyClass("url1"); new MyClass("url1"); // 复用已有实例,不会执行构造逻辑 new MyClass("url22222");
说明:
- 使用私有静态属性
#instances(ES2022+支持)存储缓存,避免外部篡改,比外部数组更安全优雅 - 构造函数中通过
return已有实例,覆盖了默认返回新创建this的行为,实现复用 - 完全保留
new的调用语法,对原有代码侵入性低
方式二:静态工厂方法(语义更明确)
如果不想修改构造函数的默认行为,可以提供一个静态工厂方法,专门负责获取/创建实例:
class MyClass { static #instances = new Map(); constructor(url) { this.url = url; console.log("Constructing MyClass with", url); } // 静态工厂方法:获取对应url的实例 static getInstance(url) { if (!MyClass.#instances.has(url)) { MyClass.#instances.set(url, new MyClass(url)); } return MyClass.#instances.get(url); } } // 测试代码 MyClass.getInstance("url1"); MyClass.getInstance("url1"); // 复用实例 MyClass.getInstance("url22222");
说明:
- 构造函数保持原有逻辑,语义更清晰:
new始终创建新实例,getInstance负责复用 - 适合需要明确区分"创建新实例"和"获取复用实例"的场景
- 同样使用私有静态属性保证缓存的安全性
输出结果验证
运行上述任意一种代码,都会得到你期望的输出:
Constructing MyClass with url1 Constructing MyClass with url22222
额外优化建议
- 如果参数是复杂类型(而非简单字符串),可以将参数序列化为字符串作为Map的key,或使用
WeakMap(若参数是对象且允许被垃圾回收) - 如需清理缓存,可添加静态方法(如
clearInstance(url))移除指定缓存或清空所有缓存
内容的提问来源于stack exchange,提问作者greentea
相关产品推荐
相关产品推荐

