定义:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
实现单例
如何实现单例?
无非是用一个变量来标识当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。
class Singleton {
instance = null;
static getInstance() {
if (!this.instance) {
this.instance = new Singleton()
}
return this.instance
}
prototypeMethods() {
console.log('Mes')
}
}
console.log(Singleton.getInstance() === Singleton.getInstance()) // true
这里的 instance
属性就是那个实例是否创建的标识。单例的核心代码如下:
let instance;
if(!instance){
instance = xxx
}
应用:
- 登录框 :无论点击多少次,就只有一个登录弹框;
- Vuex:单一数据源;
登录框:
class LoginForm {
instance = null;
static showLogin() {
if (this.instance) {
return this.instance;
}
this.createForm();
return (this.instance = this);
}
static createForm() {
console.log("create");
let form = document.createElement("div"),
input = document.createElement("input");
input.placeholder = '输入用户名'
form.appendChild(input);
document.body.appendChild(form);
}
}
LoginForm.showLogin()
Vue 中单例组件:
扩展
如何把本来不是一个单例的函数如何改造为一个单例呢,难道要像上面添加标识和方法吗?如果都这样做的话有点麻烦,我们可以抽象一个单例工厂方法:
function SingletonFactory(fn) {
if (!fn.instance) {
fn.instance = new (Function.prototype.bind.apply(fn, arguments));
}
return fn.instance
}
案例:
class Fun {
constructor(project, year) {
this.project = project;
this.year = year;
}
say() {
console.log("Fun say", this.project);
}
}
console.log(SingletonFactory(Fun, "前端黑板报", 2017) == SingletonFactory(Fun, "前端黑板报", 2017))
注:new 的时候传入参数,参考 https://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible 。
或者:
let getSingle = function(fn){
let result;
return function(){
return result || (result = fn.apply(this,arguments))
}
}
使用:
function Test() {
console.log(1)
return this
}
let getSingleTest = getSingle(Test)
console.log(getSingleTest() == getSingleTest()) // 1 true
或者使用代理类:
let ProxySingleton = (function () {
let instance
return function (fn) {
if (!instance) {
instance = new (Function.prototype.bind.apply(fn, arguments))();
}
return instance
}
}())
使用:
function Test(...args) {
//console.log(args)
}
console.log(new ProxySingleton(Test,1,2) === new ProxySingleton(Test,1,2)) // true