核心思想:
限制类实例化次数只能一次,一个类只有一个实例,并提供一个访问它的全局访问点。
至于单例模式的优缺点什么的在这里咱就不过多的去说了,来看看实现方式吧,理解了之后,大家自然就知道该把单例模式用在什么地方了
实现方式:
使用一个变量存储类实例对象(值初始为 null/undefined
)。进行类实例化时,判断类实例对象是否存在,存在则返回该实例,不存在则创建类实例后返回。多次调用类生成实例方法,返回同一个实例对象。
看代码:
let CreateSingle = (function(){
let instance;//开关
return function(name){
if(instance){//判断实例是否已经存在
return instance;
}
this.name = name;//类的业务逻辑
return instance = this;//实例化之后关闭开关,不允许再次实例化
}
})();
let lili = new CreateSingle('lili');
let wuyou = new CreateSingle('wuyou');
console.log(wuyou);// lili
首先用一个自执行函数来创建了一个闭包环境,这样的话我们可以有一个开关来判断这个实例是不是已经存在了,并且还不会污染全局变量。
首先用开关来判断 类是否已经实例化,如果已经实例化过了,那么直接关闭开关,不允许再次实例化就可以了
比如:
let lili = new CreateSingle('lili');
let wuyou = new CreateSingle('wuyou');
console.log(wuyou);// lili
可以看到虽然实例化了两次,但是后面这一次实例化得到的对象还是之前第一次实例化的对象,所以得到的名字还是 lili
这样我们就实现单例模式了。
不过上面的这个写法有点乱,控制函数和我们实际的类混在一起了,把它们分开的话可能会更好,我们可以这样写:
let CreateSingle = (function(){
let instance;
return function(name){
if(instance){
return instance;
}
return instance = new Single(name);
}
})();
let Single = function(name){
this.name = name;
}
let lili = new CreateSingle('lili');
let wuyou = new CreateSingle('wuyou');
console.log(wuyou);// lili
下面的 Single 是我们实际的类,用来写我们的业务逻辑,上面的 CreateSingle 才是控制单例的函数,经过它的包装之后,我们的Single就只能被实例化一次了
let lili = new CreateSingle('lili');
let wuyou = new CreateSingle('wuyou');
console.log(wuyou);// lili
这时候我们的业务逻辑就可以分开来写,不会受到影响
来个小案例:
let CreateSingle = function(fn){
let instance;
return function(name){
return instance || (instance = new fn(name));
}
};
let Single = function(text){
let msg = document.createElement('div');
msg.innerHTML = text;
msg.style.display = 'none';
document.body.appendChild(msg);
return msg;
}
let msgBox = CreateSingle(Single);
document.onclick = function(){
let msgEl = msgBox('这里是弹窗的内容');
msgEl.style.display = 'block';
}
这样写的话呢,控制函数和类也充分解耦了,类的方法也可以随意拓展