介绍
该单是最知名的设计模式之一。有时您只需要一个类的实例,仅此而已。这一类可以是某种资源管理器或某种值的全局查找。这就是单身人士的用武之地。
在本文中,您将了解什么是单例以及如何在 JavaScript 中最好地实现它们。
先决条件
要成功完成本教程,您需要具备以下条件:
- 对 JavaScript 编码的理解。如果您需要进一步扩展您在该领域的知识,请查看此JavaScript 系列。
- 了解类在 JavaScript 中的工作方式。这个理解 JavaScript 中的类教程可以提供这一点。
理解单身人士
单例用于创建一个不存在的类的实例,否则返回现有实例的引用。这意味着在应用程序运行期间在全局范围内只创建一次单例。
基于这个定义,单例看起来与全局变量非常相似。您可能想知道为什么应该在具有全局变量的编码语言中使用单例。有一些事情使单例与全局变量不同:
- 全局变量是词法范围的,而单例不是。这意味着如果在编程块内还有另一个与全局变量同名的变量,则优先考虑第一个引用。但是,单身人士不应重新声明该引用。
- 单例的值是通过方法修改的。
- 单例在程序终止之前不会被释放,这可能不是全局变量的情况。
即使在支持全局变量的语言中,单例也非常有用。有些情况下单例很方便。单例的一些应用是记录器对象或配置设置类。
声明单身人士
有几种方法可以声明单例。这是您可能会看到的一种格式:
var SingletonInstance = {
method1: function () { ... }
method2: function () { ... }
};
这个单身人士会像这样被记录到控制台:
console.log(SingletonInstance.method1());
console.log(SingletonInstance.method2());
最好记住,这不是声明单例的最佳方式。另一种方法是使用一次创建单例的工厂类。
var SingletonFactory = (function(){
function SingletonClass() {
// ...
}
var instance;
return {
getInstance: function(){
if (!instance) {
instance = new SingletonClass();
delete instance.constructor;
}
return instance;
}
};
})();
这是第一个示例的更好替代方案,因为类定义是私有的,并且在创建第一个实例后删除了构造函数。这将防止在程序中创建重复的单例。这种方法的缺点是它与工厂模式非常相似。
还有第三种方法。这种方法实现了 ES6 类和Object.freeze()
方法的组合:
class Singleton {
constructor() {
// ...
}
method1() {
// ...
}
method2() {
// ...
}
}
const singletonInstance = new Singleton();
Object.freeze(singletonInstance);
该Object.freeze()
方法防止修改对象的属性和值。因此,应用Object.freeze()
到singletonInstance
意味着您以后将无法在代码中更改其任何属性或值。
您可以更进一步,将此单例编写为一个模块,并使用 ES6 导出功能将其导出:
export default singletonInstance;
然后这个单例可以通过导入在一个单独的文件中使用:
import mySingleton from './script.js';
mySingleton.method1();
使用这三种创建单例的方法,选择最适合您的特定用例的方法,以实现高可读性。
结论
在 JavaScript 代码中使用单例并不总是必要的。在不影响应用程序状态的地方使用单例。这种限制严重限制了它们在大型应用程序中的使用。
使用工具包中的这种基本设计模式,您可能想探索JavaScript 中的工厂模式。如果你有兴趣了解更多关于状态的管理,检查出这些文章的状态管理与终极版作出反应,并与之反应钩状态管理。