使用AOP改善javascript代码


Posted in Javascript onMay 01, 2015

Aop又叫面向切面编程,用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被严重忽视的技术点,这篇就通过下面这几个小例子,来说说AOP在js中的妙用.

1, 防止window.onload被二次覆盖.
2,无侵入的统计代码.
3, 分离表单请求和校验.
4,给ajax请求动态添加参数.
5,职责链模式.
6, 组合代替继承.

先给出before和after这2个“切面”函数. 顾名思义,就是让一个函数在另一个函数之前或者之后执行,巧妙的是,before或者after都可以和当前的函数公用this和arguments, 这样一来供我们发挥的地方就多着了.

使用AOP改善javascript代码

处理window.onload被二次覆盖.

前段时间看到QQ群里有个人问问题,要改写window.onload, 怎么才能不把以前的window.onload函数覆盖掉.

最原始的方案肯定是直接在原来的window.onload里添上你的新代码.

使用AOP改善javascript代码

这样的坏处非常明显,需要去改动原有的函数, 是侵入性最强的一种做法.

另外一种稍微好点的方案是用中间变量保存以前的window.onload;

使用AOP改善javascript代码

这样一来,多了一个讨厌的中间变量__onload, 来管理它也要花费一些额外的成本.

试想一下这个场景,当人觉得天气冷,出门的时候很自然选择穿上一件貂皮大衣,而不是把自己的皮扯掉换成貂皮. 动态装饰的好处就体现出来了,完全不会侵入之前的函数.

使用AOP改善javascript代码

无侵入的统计代码

本身跟逻辑没有任何关联的统计代码要被硬插进函数里, 这点相信很多搞过上报的同学都很不爽. 比如下面这段代码, 用来统计一个创建1000个节点的函数在用户的电脑上要花费多少时间.

使用AOP改善javascript代码

用aop的方式,不再需要在函数内部做改动,先定义一个通用的包装器.

使用AOP改善javascript代码

只要一行代码,便能给任何函数都加上统计时间的功能.

使用AOP改善javascript代码

分离表单请求和校验

我们在提交表单之前经常会做一些校验工作,来确定表单是不是应该正常提交. 最糟糕的写法是把验证的逻辑都放在send函数里面.

使用AOP改善javascript代码

而更好的方式是把所有的校验规则用策略模式放到一个集合里,返回false或者true来决定是否通过验证. 这样可以随意的选择和更换校验规则.

使用AOP改善javascript代码

这样还有一个缺点,校验和发送请求这2个请求耦合到了一个函数里面, 我们用aop来把它们分离开来, 把validata做成插件化,真正的即插即用. 只需把send函数改成:

使用AOP改善javascript代码

过最前面Function.prototype.before的代码不难看出,我们约定,当前一个函数返回false, 就会阻断下一个函数的执行, 所以当validata返回false的时候, 便不再继续执行send. 而因为之前提到的before函数可以和当前函数公用this和arguments, 所以value参数也能顺利的传递到validata函数里.

给ajax请求动态添加参数

第一个例子里window.onload是用的after后置装饰, 这里是用before前置装饰. 在ajax请求之前动态添加一些参数.

我们遇到过很多跨域的请求, jsonp和iframe都是很常用的方式. 之前在我们的项目里,用参数retype=jsonp表示是jsonp请求, retype=iframe表示是iframe请求. 除此之外这2个请求的参数没有任何区别. 那么可以用before把retype参数动态装饰进去.

先定义一个ajax请求的代理函数.使用AOP改善javascript代码

这个函数里面没有逻辑处理和分支语句,它也不关心自己是jsonp请求还是iframe请求. 它只负责发送数据, 是一个单一职责的好函数.

接下来在发送请求前放置一个before装饰器.

使用AOP改善javascript代码

开始发送请求:

使用AOP改善javascript代码

职责链模式.

职责链模式在js中典型的应用场景是事件冒泡. 将所有子节点和父节点连成一条链,并沿着这条链传递事件,直到有一个节点能够处理它为止. 职责链模式是消除过多的if else语句的神器.

拿最近做的一个需求来举例, 有个文件上传的功能, 提供了控件,html5, flash, 表单上传这4种上传方式. 根据它们的优先级以及浏览器支持情况来判断当前选择哪种上传方式. 在我进行改造之前,它的伪代码大概是这样:

使用AOP改善javascript代码

当然实际的代码远不只这么多,其中还包括了各种控件初始化,容错等情况。有天我需要屏蔽掉flash,看起来是很简单的需求,但难度实际跟在心脏旁边拆掉一根毛线血管类似.

如果试试职责链模式呢, 看看事情将变得多简单:

第一步先改写之前的after函数,使得返回一个对象时阻断职责链的传递,而返回null时继续传递请求。

使用AOP改善javascript代码

接下来把每种控件的创建方式都包裹在各自的函数中, 确保没有逻辑交叉和相互污染.

使用AOP改善javascript代码

最后用职责链把它们串起来:

使用AOP改善javascript代码

可以预见,某天我又需要屏蔽掉flash, 那时的我只需要改动这一行代码. 改成:

使用AOP改善javascript代码

组合代替继承

很多时候我们在设计程序的时候,会遇到使用组合还是继承的问题. 通常来讲, 使用组合更灵活轻巧. 还是拿之前文件上传来举例.

我定义了一个超类Upload, 衍生出4个子类.
Plugin_Upload, Html5_Upload, Flash_Upload以及Form_Upload.

Plugin_Upload会继承父类,得到Upload的大部分功能, 然后对控件上传的一些特性进行个性定制. 比如其它3种上传方式都是选择文件后便开始上传. 而控件上传在开始上传之前会经过一轮文件扫描.

第一种做法是Plugin_Upload继承Upload, 然后重写它的start_upload方法.

使用AOP改善javascript代码

用更轻的组合方式, 可以直接给原来的start_upload函数装饰上扫描功能, 甚至不需要衍生一个额外的子类.

使用AOP改善javascript代码

Javascript 相关文章推荐
jQuery 判断页面元素是否存在的代码
Aug 14 Javascript
javascript 数组排序函数sort和reverse使用介绍
Nov 21 Javascript
js在IE与firefox的差异集锦
Nov 11 Javascript
JavaScript+CSS无限极分类效果完整实现方法
Dec 22 Javascript
JavaScript中访问id对象 属性的方式访问属性(实例代码)
Oct 28 Javascript
基于hover的用法实例(推荐)
Jul 04 Javascript
Vue-router结合transition实现app前进后退动画切换效果的实例
Oct 11 Javascript
JS小球抛物线轨迹运动的两种实现方法详解
Dec 20 Javascript
JS中promise化微信小程序api
Apr 12 Javascript
vue addRoutes实现动态权限路由菜单的示例
May 15 Javascript
微信小程序项目实践之九宫格实现及item跳转功能
Jul 19 Javascript
原生JS中应该禁止出现的写法
May 05 Javascript
Javascript aop(面向切面编程)之around(环绕)分析
May 01 #Javascript
jQuery插件Zclip实现完美兼容个浏览器点击复制内容到剪贴板
Apr 30 #Javascript
jQuery插件slider实现拖动滑块选取价格范围
Apr 30 #Javascript
javascript实现验证身份证号的有效性并提示
Apr 30 #Javascript
PHP+jQuery实现随意拖动层并即时保存拖动位置
Apr 30 #Javascript
jquery实现键盘左右翻页特效
Apr 30 #Javascript
jquery Validation表单验证使用详解
Sep 12 #Javascript
You might like
在PHP中利用XML技术构造远程服务(上)
2006/10/09 PHP
在Zeus Web Server中安装PHP语言支持
2006/10/09 PHP
PHP基础知识介绍
2013/09/17 PHP
PHP SESSION的增加、删除、修改、查看操作
2015/03/20 PHP
通过修改配置真正解决php文件上传大小限制问题(nginx+php)
2015/09/23 PHP
PHP中call_user_func_array回调函数的用法示例
2016/11/26 PHP
php实现微信原生支付(扫码支付)功能
2018/05/30 PHP
PHP的PDO事务与自动提交
2019/01/24 PHP
PHP 7.4 新语法之箭头函数实例详解
2019/05/09 PHP
如何运行/调试你的PHP代码
2020/10/23 PHP
摘自百度的图片轮换效果代码
2007/11/19 Javascript
JavaScript 用Node.js写Shell脚本[译]
2012/09/20 Javascript
angularjs客户端实现压缩图片文件并上传实例
2015/07/06 Javascript
jQuery中Ajax全局事件引用方式及各个事件(全局/局部)执行顺序
2016/06/02 Javascript
JS实现屏蔽网页右键复制及ctrl+c复制的方法【2种方法】
2016/09/04 Javascript
javaScript+turn.js实现图书翻页效果实例代码
2017/02/16 Javascript
手把手搭建安装基于windows的Vue.js运行环境
2017/06/12 Javascript
javaScript实现复选框全选反选事件详解
2020/11/20 Javascript
JavaScript原型对象、构造函数和实例对象功能与用法详解
2018/08/04 Javascript
React注册倒计时功能的实现
2018/09/06 Javascript
NodeJs之word文件生成与解析的实现代码
2019/04/01 NodeJs
如何在vue 中引入使用jquery
2020/11/10 jQuery
Python导出数据到Excel可读取的CSV文件的方法
2015/05/12 Python
PyTorch学习笔记之回归实战
2018/05/28 Python
Python学习笔记之自定义函数用法详解
2019/06/08 Python
在django中,关于session的通用设置方法
2019/08/06 Python
Python脚本操作Excel实现批量替换功能
2019/11/20 Python
Python for循环与getitem的关系详解
2020/01/02 Python
python数据库编程 ODBC方式实现通讯录
2020/03/27 Python
python opencv实现图片缺陷检测(讲解直方图以及相关系数对比法)
2020/04/07 Python
Html5插件教程之添加浏览器放大镜效果的商品橱窗
2016/01/07 HTML / CSS
新农村建设指导员工作总结
2015/08/13 职场文书
幼儿园托班教育随笔
2015/08/14 职场文书
中国文明网2015年“向国旗敬礼”活动网上签名寄语
2015/09/24 职场文书
2016年区委书记抓基层党建工作公开承诺书
2016/03/25 职场文书
2016年企业安全生产月活动总结
2016/04/06 职场文书