本文参考链接:汤姆大叔的博客
深入理解JavaScript系列(25):设计模式之单例模式前言
在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象
在JavaScript里,实现单例的方式有很多种,其中最简单的一个方式是使用对象字面量的方法,其字面量里可以包含大量的属性和方法:
下面是我在 FIS从入门到放弃 这个笔记中使用的示例
//这个是一个典型的很简单的单例模式的例子
var message = {
//init 是接收参数的
init: function() {
var me = this;
console.log('message init');
me.render();
me.bind();
},
//render 是负责 render页面
render: function() {
var me = this;
me.btn = $('#btn');
},
//bind 是负责绑相应的元素
bind: function() {
var me = this;
//jQuery.proxy( function, context )
//function为执行的函数,content为函数的上下文this值会被设置成这个object对象
me.btn.on('click',$.proxy(me._go,this));
},
_go:function(e){
console.log(e.target);
}
}
//将方法导出 这个 module.exports 方法是从 layout.tpl 中引用的 mod.js 中来的
module.exports = message;
下面是我在公司项目中的首次尝试
//这里用的是单例模式中最简单的以字面量的形式进行书写的
var XYQAJS = {
//将这个对象初始化
init: function () {
var _me = this;
_me.render();
_me.bind();
_me.imgslide();
},
//提供所有需要用到的操作元素
render: function () {
var _me = this;
_me.openAskBtn = $('#openAskBtn');
_me.closebtn = $('.conform').find('.cf_closebtn');
_me.QASearchBtn = $('#QASearchBtn');
},
//将所有的事件都放到这里绑定
bind: function () {
var _me = this;
//$.proxy(_me.openpopup, this) 返回的其实是 _me.openpopup() 这个函数的上下文
//【我要提问】弹窗切换
_me.openAskBtn.on('click', $.proxy(_me.openpopup, this));
_me.closebtn.on('click', $.proxy(_me.closepopup, this));
_me.QASearchBtn.on('click', $.proxy(_me.searchkeyword, this));
},
//右侧活动轮播图
imgslide:function(){
jQuery("#slideBox1").slide({ mainCell: ".bd ul", autoPlay: true, interTime: 3000, effect: "fold", switchLoad: "_src" });
},
//打开弹窗
openpopup: function () {
$('.conformbg,.conform').show();
},
//关闭弹窗
closepopup: function () {
$('.conformbg,.conform').hide();
},
//搜索关键词
searchkeyword: function () {
var word = $('#keyword').val();
//提交数据
}
}
XYQAJS.init();
- 在浏览器的控制台中输出会发现,将所有的东西都绑在了唯一的
XYQAJS
对象上
接着我又将上面的方法写成可 new 可扩展、继承的
//这里是使用的设计模式中的单例模式进行书写的
var XYQACommon = (function(){
var _module;
if (_module) {
return _module;
}
_module = this;
//将这个对象初始化
this.init = function () {
var _me = this;
_me.render();
_me.bind();
_me.imgslide();
},
//提供所有需要用到的操作元素
this.render = function () {
var _me = this;
_me.openAskBtn = $('#openAskBtn');
_me.closebtn = $('.conform').find('.cf_closebtn');
_me.QASearchBtn = $('#QASearchBtn');
_me.listMoreBtn = $(".wbn_det").find(".morebtn");
},
//将所有的事件绑定都放到这里
this.bind = function () {
var _me = this;
//$.proxy(_me.openpopup, this) 返回的其实是 _me.openpopup() 这个函数的上下文
//【我要提问】弹窗切换
_me.openAskBtn.on('click', $.proxy(_me.openpopup, this));
_me.closebtn.on('click', $.proxy(_me.closepopup, this));
_me.QASearchBtn.on('click', $.proxy(_me.searchkeyword, this));
_me.listMoreBtn.on('click', $.proxy(_me.listMoreShow, this));
},
//右侧活动轮播图
this.imgslide = function () {
jQuery("#slideBox1").slide({ mainCell: ".bd ul", autoPlay: true, interTime: 3000, effect: "fold", switchLoad: "_src" });
},
//打开弹窗
this.openpopup = function () {
$('.conformbg,.conform').show();
},
//关闭弹窗
this.closepopup = function () {
$('.conformbg,.conform').hide();
},
//搜索关键词
this.searchkeyword = function () {
var word = $('#keyword').val();
//提交数据
},
//详情页右侧 发标公告 点击下拉展示全部
this.listMoreShow = function () {
var _hide = $(this.listMoreBtn).siblings(".wbn_det_list").not(".active");
//console.log(_hide);
if (_hide.is(":hidden")) {
_hide.slideDown(500);
} else {
_hide.slideUp(500);
}
}
return _module;
});
$(function () {
var xyqaCommon = new XYQACommon();
xyqaCommon.init();
xyqaCommon.addFn = function () {
console.log(0);
}
console.log(xyqaCommon);
var xyqaCommon2 = new XYQACommon();
console.log(xyqaCommon2);
});
- 上面的写法可以使得这个 XYQACommon 对象可 new 可扩展、继承,可以清楚的看到 xyqaCommon 执行 init 之后对象上多了那些在 render 时挂载的 jq 元素,还有就是在下面扩展了 addFn 并没有影响到宿主