单例设计模式
单例设计模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
在 JavaScript 里,有多种实现单例设计模式的方式,下面为你详细介绍:
1. 简单对象字面量实现
- 这是最简单的单例实现方式,利用对象字面量创建一个对象,该对象在整个应用程序里只会有一个实例。
const singleton = {
property: 'value',
method: function() {
return this.property;
}
};
// 使用单例
console.log(singleton.method());
2. 构造函数结合闭包实现
- 借助构造函数和闭包保证类只有一个实例。
const Singleton = (function() {
let instance;
function createInstance() {
const object = {
property: 'value',
method: function() {
return this.property;
}
};
return object;
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// 使用单例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // 输出: true
在这个例子中,Singleton 是一个立即执行函数,返回一个包含 getInstance 方法的对象。getInstance 方法会检查 instance 是否已经存在,若不存在则创建一个新实例,若存在则返回已有的实例。
3. ES6 类实现
- 在 ES6 中,可以使用类和静态方法来实现单例模式。
class Singleton {
constructor() {
if (!Singleton.instance) {
this.property = 'value';
Singleton.instance = this;
}
return Singleton.instance;
}
method() {
return this.property;
}
}
// 使用单例
const instance3 = new Singleton();
const instance4 = new Singleton();
console.log(instance3 === instance4); // 输出: true
// 在这个例子中,Singleton 类的构造函数会检查 Singleton.instance 是否已经存在,
// 若不存在则创建一个新实例并将其赋值给 Singleton.instance,若存在则返回已有的实例。
4. 使用 WeakMap 实现
- WeakMap 可用来存储对象的私有数据,能够借助它实现单例模式,保证单例的私有性。
const Singleton = (function() {
const instanceMap = new WeakMap();
class SingletonClass {
constructor() {
if (instanceMap.has(this)) {
return instanceMap.get(this);
}
this.property = 'value';
instanceMap.set(this, this);
}
method() {
return this.property;
}
}
return SingletonClass;
})();
// 使用单例
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2);
在这个示例中,运用 WeakMap instanceMap 来存储单例实例。当创建 SingletonClass 的新实例时,会先检查 instanceMap 里是否已有该实例,若有则返回已有实例,若无则创建新实例并将其存入 instanceMap。
5. 模块模式实现
在 JavaScript 模块系统里,模块只会被加载一次,这就保证了模块内部的变量和函数只有一个实例,能够利用这个特性实现单例模式。
// singletonModule.js
const singleton = {
property: 'value',
method: function() {
return this.property;
}
};
export default singleton;
// main.js
import singleton from './singletonModule.js';
console.log(singleton.method());
6. 使用 Proxy 实现
- 可以借助 Proxy 来拦截对象的创建过程,以此保证对象只有一个实例。
const Singleton = new Proxy(function() {}, {
instance: null,
construct(target, args) {
if (!this.instance) {
this.instance = new target(...args);
}
return this.instance;
}
});
class MyClass {
constructor() {
this.property = 'value';
}
method() {
return this.property;
}
}
const instance1 = new (Singleton(MyClass))();
const instance2 = new (Singleton(MyClass))();
console.log(instance1 === instance2);
在这个示例中,使用 Proxy 拦截了对象的构造过程,当第一次创建对象时,会创建一个新实例并存储在 instance 属性中,后续再创建对象时,会直接返回已有的实例。