本文参考链接:汤姆大叔的博客
深入理解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 并没有影响到宿主


