期待的单例
import { CreateSingle } from './single.js'
const single1 = new CreateSingle()
const single2 = new CreateSingle()
console.log(single1 === single2) // 期待是true
期待是true,可惜是false.
如果CreateSingle是个普通的class类,那么new出来的对象都没关联.
不完善的单例1
class CreateSingle {
constructor() {
console.log('我创建了个单例')
}
}
const single = new CreateSingle()
export { single }
这样外面引入了几次的single,constructor构造器只会执行一次,但是有个问题是,我们把生成单例的时机提前了,瑕疵.
不完善的单例2
在其他面向对象语言中如果想实现单例,只要把constructor设为private私有化,强制用户使用方法去获取单例即可:
class CreateSingle {
private constructor() {
console.log('我创建了个单例')
}
static _ins = null
static getInstance() {
if(!this._ins) {
this._ins = new CreateSingle()
}
return this._ins
}
}
但是由于js中无法对构造器私有化,如果有人执行了new CreateSingle(),就打破了单例.不过受此启发,我们可以用一个函数利用闭包来生成个单例.
class _CreateSingle {
constructor() {
console.log('我创建了个单例')
}
// ...
}
function createSingleFn() {
let _ins
return class {
constructor(...args) {
if(!_ins) {
_ins = new _CreateSingle(...args)
}
return _ins
}
}
}
const CreateSingle = createSingleFn()
export { CreateSingle }
这样new出来的两个对象都相等了,可惜还是有瑕疵:
import { CreateSingle } from './single.js'
const single = new CreateSingle()
CreateSingle.prototype.add = function () {}
single.add() // error报错 single下没有add
因为我们CreateSingle其实是函数内部返回的匿名class类,而我们的单例实则是_CreateSingle类,两者断开了联系无不相关.
利用代理解决实现单例
还是用上个例子的思路,但是把匿名class改为proxy,利用construct方法拦截new操作符.
// ...
function createSingleFn() {
let _ins
return new Proxy(_CreateSingle, {
construct(target, args) {
if(!_ins) {
_ins = new target(...args)
}
return _ins
}
})
}