什么是单例模式
单例模式属于创建型模式,是一种创建对象的方式。单例对象的类只允许创建一个实例。
以java系统为例,倘若有个创建资源消耗较高的常用对象(如数据库连接),若是每次用到时临时创建,则频繁的对象销毁和创建行为会非常的消耗性能。
而做成单例模式:不允许用new语句来创建对象,而是该类自身创建一个对象之后保存起来,再暴露一个获取该对象的方法给到全局。则全局只需进行一次对象创建工作。
##JavaScript中单例模式的问题
在java等语言中,单例模式的作用很好理解。但是在js里却很尴尬了,
我找到的大部分人给出的单例模式的定义里面都会反复的出现“类”这个字眼,而js里甚至没有真正的类(es6的class只是一个语法糖,并不是真正的类)。
这是由于java是基于类的面向对象,而js是基于原型的面向对象,并且js还是个弱类型语言。
面向对象的设计模式几乎都是针对前者而设计的,若把其照搬到后者进行使用很容易显得怪异。
比如在js中创建一个对象并不需要先定义一个类,而是可以直接写一个字面量对象。
let person = {
age: 10
}
某种意义上来说,这已经是个单例模式了,你没办法再创建一个和它同类的对象,因为js中连类都没有。但是按这么说的话,js里的对象基本都是单例的。
JavaScript的单例模式
其他语言中的单例模式是无法照搬过来的,只能领会其精神后进行变通。
假如将其理解成:每次获取一个对象的时候都返回之前的对象,则可以用闭包来实现。
function getSingleton(fn) {
var instance = null;
return function() {
if (!instance) {
instance = fn(...arguments);
}
return instance;
}
}
然后每次如此调用
let createPerson = getSingleton((age) => {
let person = {
age: age
}
return person;
});
console.log(createPerson(10))
// {age:10}
console.log(createPerson(11))
// {age:10}
console.log(createPerson(12))
// {age:10}
这样每次获取对象的时候都会返回第一次创建的对象,表现和java中的单例模式是十分相似的。
不过这段逻辑的应用场景是非常非常少的,因为这只是看起来和java中的单例模式相似,而内在却是完全不同的。
java中的单例模式是为了解决某些场景下创建对象时存在的问题,而在js中本就没这些问题,所以注定只能模仿到表面而不能模仿到灵魂,显得画蛇添足。
我也看过很多人写的js中的单例模式,大都是对java中单例模式表现的模仿,感觉应用面都很狭窄。
所以准确的说,只能说前端的很多场景:例如每次弹的提示窗都使用同一个DOM,不要销毁掉下次重新创建出来。类似的这些场景广泛的用到了和“单例模式”相似的思想,
但是js里并不存在一个真正意义上的“单例模式”,所以也就不存在一个固定的js的“单例模式实现方案”。
吐槽
单例模式由于简单好记,很多人甚至面试罗列设计模式的时候说的第一个就是“单例模式”。
但是狭义的单例模式在js里面并不存在。这是由语言的特性导致的。
所以有的初学者学到这里可能会一脸懵逼,觉得这个设计模式是多此一举,不明白含义。这其实就是照抄其他语言设计模式的结果。也并不是说每个设计模式在所有的面向对象的语言里面都适用,个人认为这个模式不应该抄过来。