使用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 相关文章推荐
让textarea控件的滚动条怎是位与最下方
Apr 20 Javascript
JQery 渐变图片导航效果代码 漂亮
Jan 01 Javascript
不使用浏览器运行javascript代码的方法
Jul 24 Javascript
JS通过相同的name进行表格求和代码
Aug 18 Javascript
Javascript学习笔记之 对象篇(三) : hasOwnProperty
Jun 24 Javascript
jquery中one()方法的用法实例
Jan 16 Javascript
javascript中createElement的两种创建方式
May 14 Javascript
详解jQuery停止动画——stop()方法的使用
Dec 14 Javascript
JavaScript变速动画函数封装添加任意多个属性
Apr 03 Javascript
Vue中实现权限控制的方法示例
Jun 07 Javascript
webpack的pitching loader详解
Sep 23 Javascript
javascript中的相等操作符(==与===区别)
Dec 21 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
require(),include(),require_once()和include_once()区别
2008/03/27 PHP
php按字符无乱码截取中文的方法
2015/03/27 PHP
PHP通过串口实现发送短信
2015/07/08 PHP
php图像处理函数imagecopyresampled用法详解
2016/12/02 PHP
浅谈PHP的排列组合(如输入a,b,c 输出他们的全部组合)
2017/03/14 PHP
优化网页之快速的呈现我们的网页
2007/06/29 Javascript
Javascript 读后台cookie代码
2008/09/15 Javascript
javascript中的关于类型转换的性能优化
2010/12/14 Javascript
ANT 压缩(去掉空格/注释)JS文件可提高js运行速度
2013/04/15 Javascript
jQuery选择器源码解读(六):Sizzle选择器匹配逻辑分析
2015/03/31 Javascript
jquery超简单实现手风琴效果的方法
2015/06/05 Javascript
javascript检测flash插件是否被禁用的方法
2016/01/14 Javascript
js一维数组、多维数组和对象的混合使用方法
2016/04/03 Javascript
js调用屏幕宽度的简单方法
2016/11/14 Javascript
Node.js中如何合并两个复杂对象详解
2016/12/31 Javascript
React 使用Hooks简化受控组件的状态绑定
2019/03/18 Javascript
微信小程序--特定区域滚动到顶部时固定的方法
2019/04/28 Javascript
json解析大全 双引号、键值对不在一起的情况
2019/12/06 Javascript
js 计算月/周的第一天和最后一天代码
2020/02/01 Javascript
Python将DataFrame的某一列作为index的方法
2018/04/08 Python
python3 读写文件换行符的方法
2018/04/09 Python
python 获取一个值在某个区间的指定倍数的值方法
2018/11/12 Python
python如何制作缩略图
2019/04/30 Python
Python3 A*寻路算法实现方式
2019/12/24 Python
利用Python自动化操作AutoCAD的实现
2020/04/01 Python
解决使用Pandas 读取超过65536行的Excel文件问题
2020/11/10 Python
纯CSS3实现的阴影效果
2014/12/24 HTML / CSS
Html5 Geolocation获取地理位置信息实例
2016/12/09 HTML / CSS
html5 冒号分隔符对齐的实现
2019/07/31 HTML / CSS
一年级数学教学反思
2014/02/01 职场文书
中秋节礼品促销方案
2014/02/02 职场文书
党课知识竞赛主持词
2014/04/01 职场文书
令人印象深刻的自荐信
2014/05/25 职场文书
社区护士演讲稿
2014/08/27 职场文书
先进事迹演讲稿
2014/09/01 职场文书
Python+SeaTable实现计算两个日期间的工作日天数
2022/07/07 Python