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一样包装一层.

用AOP改善javascript代码的更多相关文章

  1. [转]用AOP改善javascript代码

    有时候,不光要低头写代码,也要学着站在更高的角度,来思考代码怎么写,下面这篇文章,讲的关于代码设计的问题,脑洞大开. 原文: http://www.alloyteam.com/2013/08/yong ...

  2. (第一章)改善JavaScript,编写高质量代码。

    根据<编写高质量代码改善JavaScript程序的188个建议>这本书,来记录我目前所了解的建议方式. 建议1:警惕Unicode乱码 根据ECMA标准规定JavaScript语言可以使用 ...

  3. 读《编写高质量代码:改善JavaScript程序的188个建议》1

    建议3:减少全局变量污染 定义全局变量有3种方式: ❑在任何函数外面直接执行var语句. var f='value'; ❑直接添加一个属性到全局对象上.全局对象是所有全局变量的容器.在Web浏览器中, ...

  4. 大量javascript代码的项目如何改善可维护性

    项目中有点javascript文件,javascript代码行数达到7000多行,维护很费力,主要体现在以下几个方面: 1,方法没有注释,没有注释方法的作用,从上到下罗列,很难知道这个方法应该啥时候调 ...

  5. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...

  6. 高质量JavaScript代码书写基本要点

    翻译-高质量JavaScript代码书写基本要点 by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/ ...

  7. 以优美方式编写JavaScript代码

    英文原文:CoffeeScript: The beautiful way to write JavaScript 我用 JavaScript 编程很多年了,写了大量的 JavaScript 代码,即便 ...

  8. [转] 翻译-高质量JavaScript代码书写基本要点 ---张鑫旭

    by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=1173 原文作者:St ...

  9. 高质量JavaScript代码书写基本要点学习

    高质量JavaScript代码书写基本要点学习 可维护的代码意味着: •可读的 •一致的 •可预测的 •看上去就像是同一个人写的 •已记录   最小全局变量(Minimizing Globals)   ...

随机推荐

  1. Benelux Algorithm Programming Contest 2014 Final(第二场)

    B:Button Bashing You recently acquired a new microwave, and noticed that it provides a large number ...

  2. 三维偏序(陌上花开) CDQ分治

    十分巧妙. Code: #include <cstdio> #include <algorithm> #include <cstring> #define setI ...

  3. JavaScript:理解事件循环

    话说js是单线程的,它通过浏览器事件循环轮询事件队列,来实现异步.然而,事件循环的时机是什么时候?浏览器是如何帮助JS引擎线程实现异步的? 浏览器页面进程的四个线程 首先说一下,chrome会为每一个 ...

  4. Python3 利用POP3与smtplib进行计算机远程控制

    初习,代码有不足之处,欢迎指出. 跟大家分享的是,通过发送端发送cmd命令,从而对接收端进行cmd命令的控制. #接收端代码 from poplib import POP3 import time,o ...

  5. Unity 编辑器学习(二)之 全局光照(GI)

    光影流年,花影阡陌.光与影交织的岁月教育我们,不会使用光照的程序员不是个好美术. 一.概述 点击 Window > Lighting > Settings 会弹出Lighting窗口,这个 ...

  6. 坑爹的RockSaw和坑爹的windows7

    坑爹的RockSaw和坑爹的windows7 http://chen4w.iteye.com/blog/1153433

  7. [Poi] Build and Analyze Your JavaScript Bundles with Poi

    Ever wonder where those extra KB in your bundle are coming from? This lesson walks you through runni ...

  8. vim 插件之 surround.vim

    surround.vim-这个插件主要是用来插入一些特殊符号的(成对出现) 下载地址 http://www.vim.org/scripts/script.php?script_id=1697 http ...

  9. Android TextureView简易教程

    如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的TextureView做到. TextureView的兄弟SurfaceView 应用程序的视频或者o ...

  10. Centos7 zabbix3.4.6的安装部署 (一)

    部署zabbix主要为了监控日常主机.服务器.Web服务器.数据库.路由器.交换机等日常设备,功能强大,稳定性好 现在通过使用虚拟机VM搭建的Centos7部署zabbix服务 实现简单监控功能 本章 ...