《JavaScript设计模式与开发实践》整理


最近在研读一本书《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)单例模式

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式的核心是确保只有一个实例,并提供全局访问。

惰性单例。

demo代码

 

2)策略模式

定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

这句话如果说得更详细一点,就是:定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对 Context 发起请求的时候,Context 总是把请求委托给这些策略对象中间的某一个进行计算。

计算奖金、缓动动画、表单校验。

demo代码

 

3)代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象。

保护代理和虚拟代理,虚拟代理实现图片预加,缓存代理,用高阶函数动态创建代理。

demo代码

 

4)迭代器模式

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素。

内部迭代器和外部迭代器,

demo代码

 

5)发布—订阅模式

发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

DOM事件, 自定义事件,通用实现。

demo代码

 

6)命令模式

命令模式中的命令(command)指的是一个执行某些特定事情的指令。

命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。

此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。

菜单程序,撤消命令,命令队列。

demo代码

 

7)组合模式

组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。

除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性。

宏命令,扫描文件夹。

demo代码

 

8)模版方法模式

模板方法模式是一种只需使用继承就可以实现的非常简单的模式。

模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。

在模板方法模式中,子类实现中的相同部分被上移到父类中,而将不同的部分留待子类来实现。这也很好地体现了泛化的思想。

Coffee or Tea,钩子方法,好莱坞原则。

demo代码

 

9)享元模式

享元(flyweight)模式是一种用于性能优化的模式,“fly”在这里是苍蝇的意思,意为蝇量级。

享元模式的核心是运用共享技术来有效支持大量细粒度的对象。

通用结构,通用对象池。

demo代码

 

10)职责链模式

职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

职责链的实现,用AOP实现职责链

demo代码

 

11)中介者模式

中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。

泡泡堂。

demo代码

 

12)装饰者模式

装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。

飞机大战,装饰函数,用AOP 装饰函数 。

demo代码

 

13)状态模式

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

第一部分的意思是将状态封装成独立的类,并将请求委托给当前的状态对象,当对象的内部状态改变时,会带来不同的行为变化。

第二部分是从客户的角度来看,我们使用的对象,在不同的状态下具有截然不同的行为,这个对象看起来是从不同的类中实例化而来的,实际上这是使用了委托的效果。

通用结构,文件上传,JavaScript 版本的状态机。

demo代码

 

14)适配器模式

适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎样实现的,也不考虑它们将来可能会如何演化。

适配器模式不需要改变已有的接口,就能够使它们协同作用。