单例模式通过将实例缓存于构造函数自身而非原型上实现唯一性,确保无论new调用或直接调用都返回同一实例;原型链仅用于方法复用,不参与单例控制。

单例模式的核心是确保一个类只有一个实例,并提供全局访问点。用原型链实现单例,关键在于把实例缓存到构造函数自身(而非原型上),避免每次 new 都创建新对象。
把实例挂载在构造函数上
构造函数是函数对象,本身可作为存储容器。在构造函数内部判断是否已有实例,有则返回,没有则新建并缓存。
- 不要把 instance 放在 prototype 上——那样所有实例共享该属性,但无法控制“只创建一次”
- instance 必须挂在构造函数(如 Singleton)自身,比如 Singleton.instance
- 每次调用构造函数时检查并返回缓存实例,不使用 new 也能保证单例(但需约定调用方式)
支持 new 和直接调用的写法
让构造函数既能用 new Singleton(),也能用 Singleton(),都返回同一实例。
- 在函数体内用 this instanceof Singleton 判断是否通过 new 调用
- 如果不是 new,则直接返回缓存实例;如果是 new,且无缓存,才初始化
- 注意:new 的情况下,this 指向新对象,但我们可以忽略它,统一返回缓存实例
示例代码(简洁可用)
以下是最小可行实现:
function Singleton() {
if (Singleton.instance) {
return Singleton.instance;
}
// 初始化逻辑(仅执行一次)
this.data = Math.random();
Singleton.instance = this;
}
// 可选:添加方法到原型,所有实例共享行为
Singleton.prototype.getData = function() {
return this.data;
};
// 使用方式(两种等效)
const a = new Singleton();
const b = Singleton();
console.log(a === b); // true
注意原型链本身不负责单例,只是辅助复用方法
原型链在这里的作用是让所有单例实例共享方法(节省内存),但单例控制逻辑完全由构造函数内部的实例缓存决定。
- prototype 不参与“唯一性”控制,只负责行为复用
- 如果误把 instance 放在 prototype 上(如 this.constructor.prototype.instance),会导致多个实例互相覆盖,不可靠
- 真正起作用的是函数对象自身的属性,和原型链无关











