本文基于你已经知道单例模式的要点,本文内容借鉴于《javascript设计模式与开发实践》这本书,做出了整理和一些思考。
建议阅读时间:10-15min
惰性单例是指需要的时候才创建对象实例。这种技术非常好用,而且在实际开发中被大范围的使用。
比如我们借鉴这种思想,实例对象是需要的时候才被创建而不是开始就创建,所以优化后的写法是这样的。
Singleton.getInstance = (function(){
let instance = null;
return function(name){
if(!instance){
instance = new Singleton(name)
}
return instance
}
}
)()
下面的案例我们将结合页面中最常见的登录窗来进行说明。显然它符合单例的基本要求。
备注 :为了简化语法,假设是在jq库下。
let loginLayer = (function(){
let $div = $("<div></div>") ;
$div.html('我是登录弹窗').css("display","none") ;
$("body").append($div);
return $div;
})()
$("#login").click(function(){
loginLayer.show();
})
上面的方法中,很显然是页面载入必然创建,而我们有些场景下是不需要登录弹窗的。
let loginLayer = function(){
let $div = $("<div></div>") ;
$div.html('我是登录弹窗').css("display","none") ;
$("body").append($div);
return $div;
}
$("#login").click(function(){
let loginLayer = loginLayer();
loginLayer.show();
})
那么如何确认页面中是否已经有一个弹窗?这时候就需要一个全局变量来记录是否已经创建过。
let loginLayer = (function(){
let $div ;
return function(){
if(!$div){
$div = $("<div></div>") ;
$div.html('我是登录弹窗').css("display","none") ;
$("body").append($div);
}
return $div;
}
})()
$("#login").click(function(){
loginLayer.show();
})
上面的思考中,我们完成了一个较好的单例模式的实践,但是其不具有良好的通用性,在下次创建一个iframe或者其他控件的时候,我们还是需要把它代码复制粘贴一遍。
所以我们看下是否有更好的思路,能够比较符合单一职责原则,创建对象和管理单例的逻辑都放到一个工具函数中管理?答案是肯定的。
首先分析单例的核心逻辑 :
let obj ;
if(!obj){
obj = xxx;
}
实现单例函数的核心逻辑 :
let getSingle = function (fn){
let result ;
return function(){
return result || (result = fn.apply(this,arguments));
}
}
上述的通用函数可以用于各个场景,创建对象,绑定事件都可以。
比如 :只绑定一次的事件,不想因为每次追加事件重复绑定 。
原来的写法 需要借助jq one
let bindEvent = function(){
$("div").one("click",function(){
alert("click")
})
}
let render = function (){
console.log("渲染数据");
bindEvent();
}
现在写法可以是 :
let bindEvent = getSingle(function(){
$("div").click(function(){
alert("click")
})
return true;
})
let render = function (){
console.log("渲染数据");
bindEvent();
}
单例模式是一种简单但是非常实用的单例模式,特别是惰性单例,在需要的时候才创建,并且只创建一个,创建对象和管理实例放在两个不同方法中,这两个方法组合起来更能发挥单一职责和单例模式的作用。