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的操作备忘记录
Jul 04 Javascript
Struts2的s:radio标签使用及用jquery添加change事件
Apr 08 Javascript
js原生appendChild的bug解决心得分享
Jul 01 Javascript
JavaScript 判断用户输入的邮箱及手机格式是否正确
Dec 08 Javascript
jQuery中animate()方法用法实例
Dec 24 Javascript
浅析AMD CMD CommonJS规范--javascript模块化加载学习心得总结
Mar 16 Javascript
BootStrap智能表单实战系列(七)验证的支持
Jun 13 Javascript
jQuery+ajax实现实用的点赞插件代码
Jul 06 Javascript
node跨域请求方法小结
Aug 25 Javascript
详解vue移动端日期选择组件
Feb 22 Javascript
vue中实现图片和文件上传的示例代码
Mar 16 Javascript
layui上传图片到服务器的非项目目录下的方法
Sep 26 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
PHP 开源框架22个简单简介
2009/08/24 PHP
php统计时间和内存使用情况示例分享
2014/03/13 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(一)
2014/06/23 PHP
php中静态类与静态变量用法的区别分析
2015/01/15 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
2021/03/09 PHP
JavaScript Prototype对象
2009/01/07 Javascript
JavaScript中的noscript元素属性位置及作用介绍
2013/04/11 Javascript
深入理解JavaScript 闭包究竟是什么
2013/04/12 Javascript
jqGrid读取选择的多行的某个属性代码
2014/05/18 Javascript
使用JavaScript链式编程实现模拟Jquery函数
2014/12/21 Javascript
jQuery实现的感应鼠标悬停图片色彩渐显效果
2015/03/03 Javascript
ajax图片上传,图片异步上传,更新实例
2016/12/30 Javascript
jquery实现input框获取焦点的简单实例
2017/01/26 Javascript
图解Javascript——作用域、作用域链、闭包
2017/03/21 Javascript
xmlplus组件设计系列之树(Tree)(9)
2017/05/02 Javascript
将input框中输入内容显示在相应的div中【三种方法可选】
2017/05/08 Javascript
深究AngularJS——ng-checked(回写:带真实案例代码)
2017/06/13 Javascript
基于vue.js实现的分页
2018/03/13 Javascript
详解express + mock让前后台并行开发
2018/06/06 Javascript
关于JS模块化的知识点分享
2019/10/16 Javascript
基于Cesium绘制抛物弧线
2020/11/18 Javascript
如何在vue中使用kindeditor富文本编辑器
2020/12/19 Vue.js
[01:04:06]DOTA2上海特级锦标赛A组资格赛#2 Secret VS EHOME第一局
2016/02/26 DOTA
python3.6使用tkinter实现弹跳小球游戏
2019/05/09 Python
使用 CSS3 中@media 实现网页自适应的示例代码
2020/03/24 HTML / CSS
HTML5 在canvas中绘制矩形附效果图
2014/06/23 HTML / CSS
德国知名健康零食网上商店:Seeberger
2017/07/27 全球购物
BIFFI美国站:意大利BIFFI BOUTIQUES豪华多品牌时装零售公司
2020/02/11 全球购物
成人毕业生自我鉴定
2013/10/18 职场文书
产品销售员岗位职责
2013/12/18 职场文书
简历上的自我评价,该怎么写呢?
2019/06/13 职场文书
2019年聘任书的写作格式及范文!
2019/07/03 职场文书
深入浅出的讲解:信号调制到底是如何实现的
2022/02/18 无线电
Spring 使用注解开发
2022/05/20 Java/Android
Java 多线程并发FutureTask
2022/06/28 Java/Android
Win10玩csgo闪退如何解决?Win10玩csgo闪退的解决方法
2022/07/23 数码科技