本文参考链接:汤姆大叔的博客
深入理解JavaScript系列(25):设计模式之单例模式

前言

在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象

在JavaScript里,实现单例的方式有很多种,其中最简单的一个方式是使用对象字面量的方法,其字面量里可以包含大量的属性和方法:

下面是我在 FIS从入门到放弃 这个笔记中使用的示例

  1. //这个是一个典型的很简单的单例模式的例子
  2. var message = {
  3. //init 是接收参数的
  4. init: function() {
  5. var me = this;
  6. console.log('message init');
  7. me.render();
  8. me.bind();
  9. },
  10. //render 是负责 render页面
  11. render: function() {
  12. var me = this;
  13. me.btn = $('#btn');
  14. },
  15. //bind 是负责绑相应的元素
  16. bind: function() {
  17. var me = this;
  18. //jQuery.proxy( function, context )
  19. //function为执行的函数,content为函数的上下文this值会被设置成这个object对象
  20. me.btn.on('click',$.proxy(me._go,this));
  21. },
  22. _go:function(e){
  23. console.log(e.target);
  24. }
  25. }
  26. //将方法导出 这个 module.exports 方法是从 layout.tpl 中引用的 mod.js 中来的
  27. module.exports = message;

下面是我在公司项目中的首次尝试

  1. //这里用的是单例模式中最简单的以字面量的形式进行书写的
  2. var XYQAJS = {
  3. //将这个对象初始化
  4. init: function () {
  5. var _me = this;
  6. _me.render();
  7. _me.bind();
  8. _me.imgslide();
  9. },
  10. //提供所有需要用到的操作元素
  11. render: function () {
  12. var _me = this;
  13. _me.openAskBtn = $('#openAskBtn');
  14. _me.closebtn = $('.conform').find('.cf_closebtn');
  15. _me.QASearchBtn = $('#QASearchBtn');
  16. },
  17. //将所有的事件都放到这里绑定
  18. bind: function () {
  19. var _me = this;
  20. //$.proxy(_me.openpopup, this) 返回的其实是 _me.openpopup() 这个函数的上下文
  21. //【我要提问】弹窗切换
  22. _me.openAskBtn.on('click', $.proxy(_me.openpopup, this));
  23. _me.closebtn.on('click', $.proxy(_me.closepopup, this));
  24. _me.QASearchBtn.on('click', $.proxy(_me.searchkeyword, this));
  25. },
  26. //右侧活动轮播图
  27. imgslide:function(){
  28. jQuery("#slideBox1").slide({ mainCell: ".bd ul", autoPlay: true, interTime: 3000, effect: "fold", switchLoad: "_src" });
  29. },
  30. //打开弹窗
  31. openpopup: function () {
  32. $('.conformbg,.conform').show();
  33. },
  34. //关闭弹窗
  35. closepopup: function () {
  36. $('.conformbg,.conform').hide();
  37. },
  38. //搜索关键词
  39. searchkeyword: function () {
  40. var word = $('#keyword').val();
  41. //提交数据
  42. }
  43. }
  44. XYQAJS.init();
  • 在浏览器的控制台中输出会发现,将所有的东西都绑在了唯一的 XYQAJS 对象上

image.png

接着我又将上面的方法写成可 new 可扩展、继承的

  1. //这里是使用的设计模式中的单例模式进行书写的
  2. var XYQACommon = (function(){
  3. var _module;
  4. if (_module) {
  5. return _module;
  6. }
  7. _module = this;
  8. //将这个对象初始化
  9. this.init = function () {
  10. var _me = this;
  11. _me.render();
  12. _me.bind();
  13. _me.imgslide();
  14. },
  15. //提供所有需要用到的操作元素
  16. this.render = function () {
  17. var _me = this;
  18. _me.openAskBtn = $('#openAskBtn');
  19. _me.closebtn = $('.conform').find('.cf_closebtn');
  20. _me.QASearchBtn = $('#QASearchBtn');
  21. _me.listMoreBtn = $(".wbn_det").find(".morebtn");
  22. },
  23. //将所有的事件绑定都放到这里
  24. this.bind = function () {
  25. var _me = this;
  26. //$.proxy(_me.openpopup, this) 返回的其实是 _me.openpopup() 这个函数的上下文
  27. //【我要提问】弹窗切换
  28. _me.openAskBtn.on('click', $.proxy(_me.openpopup, this));
  29. _me.closebtn.on('click', $.proxy(_me.closepopup, this));
  30. _me.QASearchBtn.on('click', $.proxy(_me.searchkeyword, this));
  31. _me.listMoreBtn.on('click', $.proxy(_me.listMoreShow, this));
  32. },
  33. //右侧活动轮播图
  34. this.imgslide = function () {
  35. jQuery("#slideBox1").slide({ mainCell: ".bd ul", autoPlay: true, interTime: 3000, effect: "fold", switchLoad: "_src" });
  36. },
  37. //打开弹窗
  38. this.openpopup = function () {
  39. $('.conformbg,.conform').show();
  40. },
  41. //关闭弹窗
  42. this.closepopup = function () {
  43. $('.conformbg,.conform').hide();
  44. },
  45. //搜索关键词
  46. this.searchkeyword = function () {
  47. var word = $('#keyword').val();
  48. //提交数据
  49. },
  50. //详情页右侧 发标公告 点击下拉展示全部
  51. this.listMoreShow = function () {
  52. var _hide = $(this.listMoreBtn).siblings(".wbn_det_list").not(".active");
  53. //console.log(_hide);
  54. if (_hide.is(":hidden")) {
  55. _hide.slideDown(500);
  56. } else {
  57. _hide.slideUp(500);
  58. }
  59. }
  60. return _module;
  61. });
  62. $(function () {
  63. var xyqaCommon = new XYQACommon();
  64. xyqaCommon.init();
  65. xyqaCommon.addFn = function () {
  66. console.log(0);
  67. }
  68. console.log(xyqaCommon);
  69. var xyqaCommon2 = new XYQACommon();
  70. console.log(xyqaCommon2);
  71. });
  • 上面的写法可以使得这个 XYQACommon 对象可 new 可扩展、继承,可以清楚的看到 xyqaCommon 执行 init 之后对象上多了那些在 render 时挂载的 jq 元素,还有就是在下面扩展了 addFn 并没有影响到宿主

image.png