JavaScript设计模式之单例模式实例


Posted in Javascript onSeptember 24, 2014

《Practical Common Lisp》的作者 Peter Seibel 曾说,如果你需要一种模式,那一定是哪里出了问题。他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案。

不管是弱类型或强类型,静态或动态语言,命令式或说明式语言、每种语言都有天生的优缺点。一个牙买加运动员, 在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些。

术士和暗影牧师很容易成为一个出色的辅助,而一个背着梅肯满地图飞的敌法就会略显尴尬。 换到程序中, 静态语言里可能需要花很多功夫来实现装饰者,而js由于能随时往对象上面扔方法,以至于装饰者模式在js里成了鸡肋。

讲 Javascript 设计模式的书还比较少,《Pro javaScript Design Patterns》是比较经典的一本,但是它里面的例子举得比较??拢??越岷衔以诠ぷ髦行垂?拇?耄?盐业睦斫庾芙嵋幌隆H绻?业睦斫獬鱿至似?睿?氩涣咧刚??/p>

一、单例模式

单例模式的定义是产生一个类的唯一实例,但js本身是一种“无类”语言。很多讲js设计模式的文章把{}当成一个单例来使用也勉强说得通。因为js生成对象的方式有很多种,我们来看下另一种更有意义的单例。

有这样一个常见的需求,点击某个按钮的时候需要在页面弹出一个遮罩层。比如web.qq.com点击登录的时候.

JavaScript设计模式之单例模式实例

这个生成灰色背景遮罩层的代码是很好写的.

var createMask = function(){

return document,body.appendChild(  document.createElement(div)  );

}

$( ‘button' ).click( function(){

Var mask  = createMask();

mask.show();

})

问题是, 这个遮罩层是全局唯一的, 那么每次调用createMask都会创建一个新的div, 虽然可以在隐藏遮罩层的把它remove掉. 但显然这样做不合理.

再看下第二种方案, 在页面的一开始就创建好这个div. 然后用一个变量引用它.

var mask = document.body.appendChild( document.createElement( ”div' ) );

$( ”button' ).click( function(){

mask.show();

} )

这样确实在页面只会创建一个遮罩层div, 但是另外一个问题随之而来, 也许我们永远都不需要这个遮罩层, 那又浪费掉一个div, 对dom节点的任何操作都应该非常吝啬.

如果可以借助一个变量. 来判断是否已经创建过div呢?

var mask;

var createMask = function(){

if ( mask ) return mask;

else{

mask = document,body.appendChild(  document.createElement(div)  );

return mask;

}

}

看起来不错, 到这里的确完成了一个产生单列对象的函数. 我们再仔细看这段代码有什么不妥.

首先这个函数是存在一定副作用的, 函数体内改变了外界变量mask的引用, 在多人协作的项目中, createMask是个不安全的函数. 另一方面, mask这个全局变量并不是非需不可. 再来改进一下.

var createMask = function(){

var mask;

return function(){

return mask || ( mask = document.body.appendChild( document.createElement(‘div') ) )

}

}()

用了个简单的闭包把变量mask包起来, 至少对于createMask函数来讲, 它是封闭的.

可能看到这里, 会觉得单例模式也太简单了. 的确一些设计模式都是非常简单的, 即使从没关注过设计模式的概念, 在平时的代码中也不知不觉用到了一些设计模式. 就像多年前我明白老汉推车是什么回事的时候也想过尼玛原来这就是老汉推车.

GOF里的23种设计模式, 也是在软件开发中早就存在并反复使用的模式. 如果程序员没有明确意识到他使用过某些模式, 那么下次他也许会错过更合适的设计 (这段话来自《松本行弘的程序世界》).

再回来正题, 前面那个单例还是有缺点. 它只能用于创建遮罩层. 假如我又需要写一个函数, 用来创建一个唯一的xhr对象呢? 能不能找到一个通用的singleton包装器.

js中函数是第一型, 意味着函数也可以当参数传递. 看看最终的代码.

var singleton = function( fn ){

var result;

return function(){

return result || ( result = fn .apply( this, arguments ) );

}

}

var createMask = singleton( function(){

return document.body.appendChild( document.createElement(‘div') );

})

用一个变量来保存第一次的返回值, 如果它已经被赋值过, 那么在以后的调用中优先返回该变量. 而真正创建遮罩层的代码是通过回调函数的方式传人到singleton包装器中的. 这种方式其实叫桥接模式. 关于桥接模式, 放在后面一点点来说.

然而singleton函数也不是完美的, 它始终还是需要一个变量result来寄存div的引用. 遗憾的是js的函数式特性还不足以完全的消除声明和语句.

Javascript 相关文章推荐
jQuery操作Select选择的Text和Value(获取/设置/添加/删除)
Mar 06 Javascript
判断js中各种数据的类型方法之typeof与0bject.prototype.toString讲解
Nov 07 Javascript
js style动态设置table高度
Oct 21 Javascript
js获取域名的方法
Jan 27 Javascript
js精美的幻灯片画集特效代码分享
Aug 29 Javascript
JS实现光滑展开合拢的菜单效果代码
Sep 16 Javascript
详解JavaScript数组的操作大全
Oct 19 Javascript
jquery对象和DOM对象的相互转换详解
Oct 18 Javascript
利用js来实现缩略语列表、文献来源链接和快捷键列表
Dec 16 Javascript
Vue组件化开发思考
Feb 02 Javascript
vue中简单弹框dialog的实现方法
Feb 26 Javascript
微信小程序和H5页面间相互跳转代码实例
Sep 19 Javascript
JavaScript中实现异步编程模式的4种方法
Sep 24 #Javascript
JavaScript设计模式之观察者模式(发布者-订阅者模式)
Sep 24 #Javascript
JavaScript获取图片真实大小代码实例
Sep 24 #Javascript
再探JavaScript作用域
Sep 24 #Javascript
深入理解javascript原型链和继承
Sep 23 #Javascript
深入理解javascript构造函数和原型对象
Sep 23 #Javascript
常用的jquery模板插件——jQuery Boilerplate介绍
Sep 23 #Javascript
You might like
DC宇宙的第一个英雄,堪称动漫史鼻祖,如今成为美国文化的象征
2020/04/09 欧美动漫
PHP多线程类及用法实例
2014/12/03 PHP
浅谈Yii乐观锁的使用及原理
2017/07/25 PHP
PHP将整数数字转换为罗马数字实例分享
2019/03/17 PHP
JQuery 常用操作代码
2010/03/14 Javascript
Javascript实现通过选择周数显示开始日和结束日的实现代码
2016/05/30 Javascript
JS实现字符串转驼峰格式的方法
2016/12/16 Javascript
JS实现搜索框文字可删除功能
2016/12/28 Javascript
完美解决node.js中使用https请求报CERT_UNTRUSTED的问题
2017/01/08 Javascript
Mongoose经常返回e11000 error的原因分析
2017/03/29 Javascript
JavaScript实现父子dom同时绑定两个点击事件,一个用捕获,一个用冒泡时执行顺序的方法
2017/03/30 Javascript
springMVC + easyui + $.ajaxFileUpload实现文件上传注意事项
2017/04/23 Javascript
JavaScript实现瀑布流图片效果
2017/06/30 Javascript
React 子组件向父组件传值的方法
2017/07/24 Javascript
使用JavaScript中的lodash编写双色球效果
2018/06/24 Javascript
详解JavaScript中的强制类型转换
2019/04/15 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
2019/08/27 jQuery
jdk1.8+vue elementui实现多级菜单功能
2020/09/24 Javascript
Vue 简单实现前端权限控制的示例
2020/12/25 Vue.js
Python简单计算给定某一年的某一天是星期几示例
2018/06/27 Python
解决python3 urllib 链接中有中文的问题
2018/07/16 Python
python实现电子书翻页小程序
2019/07/23 Python
Python使用import导入本地脚本及导入模块的技巧总结
2019/08/07 Python
利用anaconda作为python的依赖库管理方法
2019/08/13 Python
python GUI库图形界面开发之PyQt5打开保存对话框QFileDialog详细使用方法与实例
2020/02/27 Python
解决阿里云邮件发送不能使用25端口问题
2020/08/07 Python
DeinDesign德国:设计自己的手机壳
2019/12/14 全球购物
如果一个类实现了多个接口但是这些接口有相同的方法名将会怎样
2013/06/16 面试题
简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程
2012/04/17 面试题
火锅店营销方案
2014/02/26 职场文书
2014年清明节网上祭英烈寄语
2014/04/09 职场文书
报表员工作失误检讨书范文
2014/09/19 职场文书
健康状况证明书
2014/11/26 职场文书
经理岗位职责
2015/02/02 职场文书
技术员岗位职责
2015/02/04 职场文书
2015年派出所工作总结
2015/04/24 职场文书