前言
设计模式是一种用来解决常见问题的模板。单例模式就是其中的一种,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。本文将会通过两个示例,来帮助你理解单例模式的概念及其在JavaScript中的实现。
正文
什么是单例模式?
举个例子,假设你在开发一款游戏,游戏中有一个分数管理器,用来记录玩家的分数。这个分数管理器应该是唯一的,因为每个玩家只能有一个分数,而这个分数需要在多个地方被访问和修改。此时,如果我们每次需要分数管理器的时候都去创建一个新的对象,那么就会产生多个分数管理器实例,这显然是不符合逻辑的。因此,我们需要确保分数管理器在整个游戏中只有一个实例,这就是单例模式的基本思想。
实现单例模式
小提一嘴
我们先来看这个例子,回顾一下new实例的过程:
function Person() {
// let obj = { // 1
// name: 'Tom'
// }
// Person.call(obj) // 2
// obj.__proto__ = Person.prototype // 4
// return obj // 5
this.name = 'Tom' // 3
}
let p1 = new Person()
let p2 = new Person()
console.log(p1 === p2); // false
每个创建的实例地址都不一样,不可能有两个相同的对象。
function Person() {
this.name = 'Tom'
}
Person.insance = 'hi'
Person.prototype.insance2 = 'hello'
let p1 = new Person()
let p2 = new Person()
console.log(p1.insance) // undefined
console.log(p1.insance2) // hello
// p1.__proto__ === Person.prototype
我们往构造函数加属性没用的,要往构造函数的原型上加new的实例才会继承到,对象的隐式原型=构造函数的显示原型。
好废话说完,进入正题,下面我们将通过两个示例来实现单例模式,第一个例子使用静态方法,第二个例子使用闭包。
示例1:使用静态方法实现单例模式
在这个示例中,我们将创建一个名为Person
的类,并在这个类中定义一个静态方法getInstance()
。这个方法会检查是否已经创建了Person
的实例,如果没有,则创建一个新的实例;如果有,则直接返回该实例。
class Person {
constructor() {
this.name = 'Tom'
}
static getInstance() {
if (!Person.instance) {
Person.instance = new Person()
}
return Person.instance
}
}
let p1 = Person.getInstance()
let p2 = Person.getInstance()
console.log(p1 === p2); // true
在这个例子中,我们通过Person.getInstance()
来获取Person
类的唯一实例。当我们首次调用getInstance()
时,会创建一个新的Person
对象,并将其存储在Person.instance
中。随后再次调用getInstance()
时,由于Person.instance
已经存在,因此不会创建新的对象,而是直接返回已有的实例。
示例2:使用闭包实现单例模式
另一个实现单例模式的方式是利用JavaScript的闭包特性。我们知道闭包
的作用是不是可以实现变量私有化,那它就可以让我们的实例一直是闭包里面的那个实例。如果不知道闭包可以看我的这篇文章<你不知道的JavaScript>,里面有介绍到this
、闭包
、调用栈
等知识点
class Person {
constructor() {
this.name = 'Tom'
}
static getInstance() {
let instance = null
return function() {
if (!instance) {
instance = new Person()
}
return instance
}
}
}
const simple = Person.getInstance()
let p1 = simple()
let p2 = simple()
console.log(p1 === p2); // true
在这个例子中,getInstance()
返回的是一个函数function
,当函数getInstance()
调用完就会出栈,因为里面的函数function
用到了 instance
变量,所有就会留一个小背包,里面装有所需要的 instance
,这个就是所谓的闭包, getInstance()
返回的函数function
赋给了simple
,然后调用,如果为空就会创建一个新的Person
对象,闭包里的instance
就为这个实例了,那么后的instance
一直不为空因此不会创建新的对象,而是直接返回闭包里的实例。
单例模式的优点与缺点
-
优点:
- 保证系统内存中该类只存在一个实例,节省内存空间;
- 控制对全局变量的访问,防止其被滥用;
- 提供一个全局访问点,方便访问。
-
缺点:
- 单例模式的类由于没有接口,所以无法继承,扩展困难;
- 违反了开闭原则,一旦单例类的功能发生变化,就需要修改代码;
总结
单例模式是一种简单而有效的设计模式,它有助于管理和优化应用程序中的资源使用。通过本文的介绍,你应该能够理解单例模式的概念以及如何在JavaScript中实现它。本文到此就结束了,希望对你有所帮助,感谢你的阅读!