最近在研读一本书《JavaScript设计模式与开发实践》,进阶用的。
一、高阶函数
高阶函数是指至少满足下列条件之一的函数。
1. 函数可以作为参数被传递。
2. 函数可以作为返回值输出。
1)高阶函数实现AOP
AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。
把这些功能抽离出来之后,再通过“动态织入”的方式掺入业务逻辑模块中。
这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块。
在 JavaScript 中实现 AOP,都是指把一个函数“动态织入”到另外一个函数之中,查看demo。
Function.prototype.before = function( beforefn ){ var __self = this; // 保存原函数的引用 return function(){ // 返回包含了原函数和新函数的"代理"函数 beforefn.apply( this, arguments ); // 执行新函数,修正 this return __self.apply( this, arguments ); // 执行原函数 } }; Function.prototype.after = function( afterfn ){ var __self = this; return function(){ var ret = __self.apply( this, arguments ); afterfn.apply( this, arguments ); return ret; } }; var func = function(){ console.log( 2 ); }; func = func.before(function(){ console.log( 1 ); }).after(function(){ console.log( 3 ); }); func();//1 2 3
2)currying
函数柯里化(function currying)又称部分求值。
一个 currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。
待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。简单点说就是返回一个函数。demo查看:
var cost = (function() { var args = []; return function() { if (arguments.length === 0) { var money = 0; for (var i = 0, l = args.length; i < l; i++) { money += args[i]; } return money; } else { [].push.apply(args, arguments); } } })(); cost(100); // 未真正求值 cost(200); // 未真正求值 cost(300); // 未真正求值 console.log(cost()); // 求值并输出:600
二、设计模式
1)单例模式
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式的核心是确保只有一个实例,并提供全局访问。
惰性单例。
2)策略模式
定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
这句话如果说得更详细一点,就是:定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对 Context 发起请求的时候,Context 总是把请求委托给这些策略对象中间的某一个进行计算。
计算奖金、缓动动画、表单校验。
3)代理模式
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。
保护代理和虚拟代理,虚拟代理实现图片预加,缓存代理,用高阶函数动态创建代理。
4)迭代器模式
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。
内部迭代器和外部迭代器,
5)发布—订阅模式
发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
DOM事件, 自定义事件,通用实现。
6)命令模式
命令模式中的命令(command)指的是一个执行某些特定事情的指令。
命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。
此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。
菜单程序,撤消命令,命令队列。
7)组合模式
组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。
除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性。
宏命令,扫描文件夹。
8)模板方法模式
模板方法模式是一种只需使用继承就可以实现的非常简单的模式。
模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。
在模板方法模式中,子类实现中的相同部分被上移到父类中,而将不同的部分留待子类来实现。这也很好地体现了泛化的思想。
Coffee or Tea,钩子方法,好莱坞原则。
9)享元模式
享元(flyweight)模式是一种用于性能优化的模式,“fly”在这里是苍蝇的意思,意为蝇量级。
享元模式的核心是运用共享技术来有效支持大量细粒度的对象。
通用结构,通用对象池。
10)职责链模式
职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
职责链的实现,用AOP实现职责链
11)中介者模式
中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。
泡泡堂。
12)装饰者模式
装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。
飞机大战,装饰函数,用AOP 装饰函数 。
13)状态模式
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
第一部分的意思是将状态封装成独立的类,并将请求委托给当前的状态对象,当对象的内部状态改变时,会带来不同的行为变化。
第二部分是从客户的角度来看,我们使用的对象,在不同的状态下具有截然不同的行为,这个对象看起来是从不同的类中实例化而来的,实际上这是使用了委托的效果。
通用结构,文件上传,JavaScript 版本的状态机。
14)适配器模式
适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎样实现的,也不考虑它们将来可能会如何演化。
适配器模式不需要改变已有的接口,就能够使它们协同作用。