Aop又叫面向切面编程,用过spring的同窗确定对它很是熟悉,而在js中,AOP是一个被严重忽视的技术点,这篇就经过下面这几个小例子,来讲说AOP在js中的妙用。
1, 防止window.onload被二次覆盖。
2,无侵入的统计代码。
3, 分离表单请求和校验。
4,给ajax请求动态添加参数。
5,职责链模式。
6, 组合代替继承。
先给出before和after这2个“切面”函数. 顾名思义,就是让一个函数在另外一个函数以前或者以后执行,巧妙的是,这2个函数能够公用this和arguments, 这样一来供咱们发挥的地方就多着了。
处理window.onload被二次覆盖。
前段时间看到QQ群里有我的问问题,要改写window.onload, 怎么才能不把之前的window.onload函数覆盖掉。
最原始的方案确定是直接在原来的window.onload里添上你的新代码。
这样的坏处很是明显,须要去改动原有的函数, 是侵入性最强的一种作法。
另一种稍微好点的方案是用中间变量保存之前的window.onload;
这样一来,多了一个讨厌的中间变量__onload, 来管理它也要花费一些额外的成本。
试想一下这个场景,当人以为天气冷,出门的时候很天然选择穿上一件貂皮大衣,而不是把本身的皮扯掉换成貂皮. 动态装饰的好处就体现出来了,彻底不会侵入以前的函数。
无侵入的统计代码
自己跟逻辑没有任何关联的统计代码要被硬插进函数里, 这点相信不少搞过上报的同窗都很不爽. 好比下面这段代码, 用来统计一个建立1000个节点的函数在用户的电脑上要花费多少时间。
用aop的方式,再也不须要在函数内部作改动,先定义一个通用的包装器。
只要一行代码,便能给任何函数都加上统计时间的功能。
分离表单请求和校验
咱们在提交表单以前常常会作一些校验工做,来肯定表单是否是应该正常提交. 最糟糕的写法是把验证的逻辑都放在send函数里面。
而更好的方式是把全部的校验规则用策略模式放到一个集合里,返回false或者true来决定是否经过验证. 这样能够随意的选择和更换校验规则。
这样还有一个缺点,校验和发送请求这2个请求耦合到了一个函数里面, 咱们用aop来把它们分离开来, 把validata作成插件化,真正的即插即用. 只需把send函数改为:
经过最前面Function.prototype.before的代码不难看出,咱们约定,当前一个函数返回false, 就会阻断下一个函数的执行, 因此当validata返回false的时候, 便再也不继续执行send。
给ajax请求动态添加参数
第一个例子里window.onload是用的after后置装饰, 这里是用before前置装饰. 在ajax请求以前动态添加一些参数。
咱们遇到过不少跨域的请求, jsonp和iframe都是很经常使用的方式. 以前在咱们的项目里,用参数retype=jsonp表示是jsonp请求, retype=iframe表示是iframe请求。
除此以外这2个请求的参数没有任何区别. 那么能够用before把retype参数动态装饰进去。
先定义一个ajax请求的代理函数。
这个函数里面没有逻辑处理和分支语句,它也不关心本身是jsonp请求仍是iframe请求. 它只负责发送数据, 是一个单一职责的好函数。
接下来在发送请求前放置一个before装饰器。
开始发送请求:
职责链模式。
职责链模式在js中典型的应用场景是事件冒泡. 将全部子节点和父节点连成一条链,并沿着这条链传递事件,直到有一个节点可以处理它为止. 职责链模式是消除过多的if else语句的神器.
拿最近作的一个需求来举例, 有个文件上传的功能, 提供了控件,html5, flash, 表单上传这4种上传方式. 根据它们的优先级以及浏览器支持状况来判断当前支持哪一种上传方式. 在我进行改造以前,它的伪代码大概是这样:
固然实际的代码远不仅这么多,其中还包括了各类控件初始化,容错等状况。有天我须要屏蔽掉flash控件,看起来是很简单的需求,但难度实际跟在心脏旁边拆掉一根毛线血管相似。
若是试试职责链模式呢, 看看事情将变得多简单:
第一步先改写以前的after函数,使得返回一个对象时阻断职责链的传递,而返回null时继续传递请求。
接下来把每种控件的建立方式都包裹在各自的函数中, 确保没有逻辑交叉和相互污染。
最后用职责链把它们串起来:
能够预见,某天我又须要屏蔽掉flash, 那时的我只须要改动这一行代码. 改为:
组合代替继承
不少时候咱们在设计程序的时候,会遇到使用组合仍是继承的问题. 一般来说, 使用组合更灵活轻巧. 仍是拿以前文件上传来举例。
我定义了一个超类Upload, 衍生出4个子类。
Plugin_Upload, Html5_Upload, Flash_Upload以及Form_Upload。
Plugin_Upload会继承父类,获得Upload的大部分功能, 而后对控件上传的一些特性进行个性定制. 好比其它3种上传方式都是选择文件后便开始上传. 而控件上传在开始上传以前会通过一轮文件扫描。
第一种作法是Plugin_Upload继承Upload, 而后重写它的start_upload方法。
用更轻的组合方式, 能够直接给原来的start_upload函数装饰上扫描功能, 甚至不须要衍生一个额外的子类。
有些同窗不喜欢扩展Function的原型, 替代方法是给before和after多增长一个参数, 或者像jquery和underscore同样包装一层