JavaScript常用的设计模式.docx

上传人:b****2 文档编号:2141622 上传时间:2022-10-27 格式:DOCX 页数:25 大小:447.50KB
下载 相关 举报
JavaScript常用的设计模式.docx_第1页
第1页 / 共25页
JavaScript常用的设计模式.docx_第2页
第2页 / 共25页
JavaScript常用的设计模式.docx_第3页
第3页 / 共25页
JavaScript常用的设计模式.docx_第4页
第4页 / 共25页
JavaScript常用的设计模式.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

JavaScript常用的设计模式.docx

《JavaScript常用的设计模式.docx》由会员分享,可在线阅读,更多相关《JavaScript常用的设计模式.docx(25页珍藏版)》请在冰豆网上搜索。

JavaScript常用的设计模式.docx

JavaScript常用的设计模式

JavaScript常用的设计模式

不管是弱类型或强类型,静态或动态语言,命令式或说明式语言、每种语言都有天生的优缺点。

一个牙买加运动员,在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些。

AD:

《PracticalCommonLisp》的作者PeterSeibel曾说,如果你需要一种模式,那一定是哪里出了问题。

他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案。

不管是弱类型或强类型,静态或动态语言,命令式或说明式语言、每种语言都有天生的优缺点。

一个牙买加运动员,在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些。

术士和暗影牧师很容易成为一个出色的辅助,而一个背着梅肯满地图飞的敌法就会略显尴尬。

换到程序中,静态语言里可能需要花很多功夫来实现装饰者,而js由于能随时往对象上面扔方法,以至于装饰者模式在js里成了鸡肋。

讲Javascript设计模式的书还比较少,《ProjavaScriptDesignPatterns》是比较经典的一本,但是它里面的例子举得比较啰嗦,所以结合我在工作中写过的代码,把我的理解总结一下。

如果我的理解出现了偏差,请不吝指正。

一单例模式

单例模式的定义是产生一个类的唯一实例,但js本身是一种“无类”语言。

很多讲js设计模式的文章把{}当成一个单例来使用也勉强说得通。

因为js生成对象的方式有很多种,我们来看下另一种更有意义的单例。

有这样一个常见的需求,点击某个按钮的时候需要在页面弹出一个遮罩层。

比如点击登录的时候.

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

1varcreateMask=function(){

2returndocument.body.appendChild(document.createElement(div));

3}

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

5Varmask=createMask();

6mask.show();

7})

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

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

8varmask=document.body.appendChild(document.createElement(''div'));

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

10mask.show();

11})

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

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

12varmask;

13varcreateMask=function(){

14if(mask)returnmask;

15else{

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

17returnmask;

18}

19}

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

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

20varcreateMask=function(){

21varmask;

22returnfunction(){

23returnmask||(mask=document.body.appendChild(document.createElement('div')))

24}

25}()

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

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

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

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

能不能找到一个通用的singleton包装器.

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

26varsingleton=function(fn){

27varresult;

28returnfunction(){

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

30}

31}

32varcreateMask=singleton(function(){

33returndocument.body.appendChild(document.createElement('div'));

34})

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

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

二简单工厂模式

简单工厂模式是由一个方法来决定到底要创建哪个类的实例,而这些实例经常都拥有相同的接口.这种模式主要用在所实例化的类型在编译期并不能确定,而是在执行期决定的情况。

说的通俗点,就像公司茶水间的饮料机,要咖啡还是牛奶取决于你按哪个按钮。

简单工厂模式在创建ajax对象的时候也非常有用.

之前我写了一个处理ajax异步嵌套的库,地址在

这个库里提供了几种ajax请求的方式,包括xhr对象的get,post,也包括跨域用的jsonp和iframe.为了方便使用,这几种方式都抽象到了同一个接口里面.

1varrequest1=Request(',''get');

2request1.start();

3request1.done(fn);

4varrequest2=Request(',''jsonp');

5request2.start();

6request2.done(fn);

Request实际上就是一个工厂方法,至于到底是产生xhr的实例,还是jsonp的实例.是由后来的代码决定的。

实际上在js里面,所谓的构造函数也是一个简单工厂。

只是批了一件new的衣服.我们扒掉这件衣服看看里面。

通过这段代码,在firefox,chrome等浏览器里,可以完美模拟new.

7functionA(name){

8this.name=name;

9}

10functionObjectFactory(){

11varobj={},

12Constructor=Array.prototype.shift.call(arguments);

13obj.__proto__=typeofConstructor.prototype==='number'?

Object.prototype

14:

Constructor.prototype;

15varret=Constructor.apply(obj,arguments);

16returntypeofret==='object'?

ret:

obj;

17}

18vara=ObjectFactory(A,'svenzeng');

19alert(a.name);//svenzeng

这段代码来自es5的new和构造器的相关说明,可以看到,所谓的new,本身只是一个对象的复制和改写过程,而具体会生成什么是由调用ObjectFactory时传进去的参数所决定的。

三观察者模式

观察者模式(又叫发布者-订阅者模式)应该是最常用的模式之一.在很多语言里都得到大量应用.包括我们平时接触的dom事件.也是js和dom之间实现的一种观察者模式.

1div.onclick=functionclick(){

2alert(''click')

3}

只要订阅了div的click事件.当点击div的时候,functionclick就会被触发.

那么到底什么是观察者模式呢.先看看生活中的观察者模式。

好莱坞有句名言.“不要给我打电话,我会给你打电话”.这句话就解释了一个观察者模式的来龙去脉。

其中“我”是发布者,“你”是订阅者。

再举个例子,我来公司面试的时候,完事之后每个面试官都会对我说:

“请留下你的联系方式,有消息我们会通知你”。

在这里“我”是订阅者,面试官是发布者。

所以我不用每天或者每小时都去询问面试结果,通讯的主动权掌握在了面试官手上。

而我只需要提供一个联系方式。

观察者模式可以很好的实现2个模块之间的解耦。

假如我正在一个团队里开发一个html5游戏.当游戏开始的时候,需要加载一些图片素材。

加载好这些图片之后开始才执行游戏逻辑.假设这是一个需要多人合作的项目.我完成了Gamer和Map模块,而我的同事A写了一个图片加载器loadImage.

loadImage的代码如下

4loadImage(imgAry,function(){

5Map.init();

6Gamer.init();

7})

当图片加载好之后,再渲染地图,执行游戏逻辑.嗯,这个程序运行良好.突然有一天,我想起应该给游戏加上声音功能.我应该让图片加载器添上一行代码.

8loadImage(imgAry,function(){

9Map.init();

10Gamer.init();

11Sount.init();

12})

可是写这个模块的同事A去了外地旅游.于是我打电话给他,喂.你的loadImage函数在哪,我能不能改一下,改了之后有没有副作用.如你所想,各种不淡定的事发生了.如果当初我们能这样写呢:

13loadImage.listen(''ready',function(){

14Map.init();

15})

16loadImage.listen(''rea

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1