JavaScript设计模式(一):单例模式
单例模式
单例模式保证一个类仅有一个实例,并且这一实例可被全局访问。
在JS
中并没有类的概念,最简单的单例模式就是声明全局变量,而为了减少全局变量的数量避免命名污染,我们常常使用以下两种方式实现单例。
1. 命名空间
使用对象字面量划分命名空间减少了全局变量的数量。
var Lean = {
event: {
addEvent: function(){ }
},
dom: {
...
}
}
2. 闭包
使用闭包暴露特定接口供外部访问。
var Lean = function(){
//私有属性
var name = 'zz';
return{
//公有方法
getName:function(){
return 'name:' + name;
}
}
}
惰性单例
惰性单例是仅在需要的时候才创建对象实例。不像前面的单例模式,页面一旦加载,单例对象就会被创建。
1. 弹框/弹出层
当我们需要一个点击弹框效果时,一般思路是先创建好这个弹框,再通过按钮注册点击事件来实现弹框的显示与隐藏。
但这种方式有一个缺陷,如果用户没有点击这一按钮,那么为弹框而创建的DOM节点都是白白浪费的。
这时候惰性单例模式就派上用场了。我们使用一个变量来判断当前是否创建过弹框。
var createPopup = (function(){
var pop;
return function(){
if(!pop){
pop = document.createElement('div');
pop.innerHTML = 'popup';
pop.style.display = 'none';
document.body.appendChild(pop);
}
return pop;
}
})();
btn.onclick = function(){
var oDiv = createPopup();
oDiv.style.display = 'block';
};
2. 封装
当我们需要创建页面上唯一的iframe
或者利用JSONP
创建script
标签来跨域请求数据时等许多场景都需要用到惰性单例模式,我们可以将其中的固定逻辑抽离出来封装成一个函数以复用。
var createSingle = function(fn){
var res;
return function(){
return res || (res = fn.apply(this, arguments));
}
};
利用闭包特性,函数中的res变量被留在内存中不会被销毁。因此可得知单例对象当前是否已经被创建。
3. 实践
现在我们来利用单例模式做一个上述弹框效果。
HTML
<body>
<button id="alert">Alert</button>
<button id="confirm">Confirm</button>
<!--<div class="wrap">
<div class="box">
<h3 class="title">提示</h3>
<div class="close">✖</div>
<p class="msg"></p>
<a class="ok" href="javascript:;">确定</a>
</div>
</div>-->
</body>
JavaScript
//类名选择器
var $ = function(sClass) {
return document.getElementsByClassName(sClass)[0];
}
//参数:弹框类型 标题 内容 回调函数
var Popup = function(sType, sTitle, sMsg, fn) {
var oWrap = document.createElement('div');
document.body.appendChild(oWrap);
oWrap.className = 'popup-wrap';
oWrap.style.display = 'none';
//根据参数确定弹框类型
if (sType == 'alert') {
oWrap.innerHTML = '...';
} else if (sType == 'confirm') {
oWrap.innerHTML = '...';
}
return oWrap;
}
//惰性单例逻辑
var createSingle = function(fn){
var res;
return function(){
return res || (res = fn.apply(this, arguments));
}
};
var createSinglePop = createSingle(Popup);
var oAlert = document.getElementById('alert');
var oConf = document.getElementById('confirm');
//注册click事件
oAlert.onclick = function(){
var o = createSinglePop('alert', 'Alert Title', 'Hello World');
o.style.display = 'block';
}
oConf.onclick = function(){
var c = createSinglePop('confirm', 'Confirm Title', 'This is confirm content', () => alert('callback'));
c.style.display = 'block';
}
JS Bin 查看效果