使用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代码
Nov 04 Javascript
jquery中ajax函数执行顺序问题之如何设置同步
Feb 28 Javascript
js检测iframe是否加载完成的方法
Nov 26 Javascript
逻辑表达式中与或非的用法详解
Jun 06 Javascript
jquery编写日期选择器
Mar 16 Javascript
vue proxyTable 接口跨域请求调试的示例
Sep 12 Javascript
详解webpack编译多页面vue项目的配置问题
Dec 11 Javascript
微信小程序中使用wxss加载图片并实现动画效果
Aug 13 Javascript
JS实现textarea通过换行或者回车把多行数字分割成数组并且去掉数组中空的值
Oct 29 Javascript
js实现倒计时器自定义时间和暂停
Feb 25 Javascript
vue.js实现备忘录demo
Jun 26 Javascript
angular4实现带搜索的下拉框
Mar 25 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  PATH_SEPARATOR判断当前服务器系统类型实例
2016/10/28 PHP
php 策略模式原理与应用深入理解
2019/09/25 PHP
JS获取父节点方法
2009/08/20 Javascript
javascript 上下banner替换具体实现
2013/11/14 Javascript
轻松创建nodejs服务器(10):处理上传图片
2014/12/18 NodeJs
Jquery实现图片预加载与延时加载的方法
2014/12/22 Javascript
jQuery读取XML文件内容的方法
2015/03/09 Javascript
JS实现Fisheye效果动感放大菜单代码
2015/10/21 Javascript
iscroll.js的上拉下拉刷新时无法回弹的解决方法
2016/02/18 Javascript
ES6记录异步函数的执行时间详解
2016/08/31 Javascript
完美解决node.js中使用https请求报CERT_UNTRUSTED的问题
2017/01/08 Javascript
详解AngularJS1.6版本中ui-router路由中/#!/的解决方法
2017/05/22 Javascript
基于vue2.0实现的级联选择器
2017/06/09 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
2017/08/10 Javascript
浅谈Vuejs Prop基本用法
2017/08/17 Javascript
微信小程序表单验证功能完整实例
2017/12/01 Javascript
node 使用 async 控制并发的方法
2018/05/07 Javascript
微信小程序实现分享朋友圈的图片功能示例
2019/01/18 Javascript
JS实现拼图游戏
2021/01/29 Javascript
以一段代码为实例快速入门Python2.7
2015/03/31 Python
Pyqt实现无边框窗口拖动以及窗口大小改变
2018/04/19 Python
pycharm中使用anaconda部署python环境的方法步骤
2018/12/19 Python
我喜欢你 抖音表白程序python版
2019/04/07 Python
Python绘制三角函数图(sin\cos\tan)并标注特定范围的例子
2019/12/04 Python
Python实现剪刀石头布小游戏(与电脑对战)
2019/12/31 Python
Python获取、格式化当前时间日期的方法
2020/02/10 Python
使用OpenCV实现道路车辆计数的使用方法
2020/07/15 Python
利用python+ffmpeg合并B站视频及格式转换的实例代码
2020/11/24 Python
详解python日志输出使用配置文件格式
2021/02/10 Python
实习生自荐信范文
2013/11/13 职场文书
科级干部考察材料
2014/02/15 职场文书
庆元旦文艺演出主持词
2014/03/27 职场文书
庆祝教师节演讲稿
2014/09/03 职场文书
考试作弊检讨书1000字(5篇)
2014/10/19 职场文书
停课通知书
2015/04/24 职场文书
大学生逃课检讨书
2015/05/04 职场文书