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

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

先给出before和after这2个“切面”函数. 顾名思义,就是让一个函数在另一个函数之前或者之后执行,巧妙的是,before或者after都可以和当前的函数公用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. 而因为之前提到的before函数可以和当前函数公用this和arguments, 所以value参数也能顺利的传递到validata函数里.

给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函数装饰上扫描功能, 甚至不需要衍生一个额外的子类.

js 实现 aop的更多相关文章

  1. JS实现AOP拦截方法调用

    //JS实现AOP拦截方法调用function jsAOP(obj,handlers) {    if(typeof obj == 'function'){        obj = obj.prot ...

  2. JS中AOP的实现和运用

    在编写js的时候,我们有时会遇到针对某种场景做处理,比如在方法开始的时候校验参数,执行方法前检查权限,或是删除前给出确认提示等等.这些校验方法.权限检测.确认提示,规则可能都是相同的,在每个方法前去调 ...

  3. A2D JS框架 - AOP封装

    AOP在js中的实现,先看看用法吧: var A2D = $.noConflict();//不要误会,此乃我自己写的A2D框架,非jQuery function fn1(name, age) { co ...

  4. js 实现 di

    前些时候有使用过AngularJS一些时间,最大的感受就是Angular完全颠覆了我们开发Web应用的方式,自己被其许多耳目一新的设计思想所折服. 首先想说的就是依赖注入(DI),这也意味着,你在使用 ...

  5. Dojo初探之3:dojo的DOM操作、query操作和domConstruct元素位置操作(基于dojo1.11.2版本)

    前言: 前面两章讲了dojo的基本规范和配置,当然这个配置不是必须的,当你有这需求的时候就可以用到dojo的config配置. dojo的所有js都是符合AMD规范进行异步加载的:http://blo ...

  6. 信息收集&Fuzz

    本文译自https://0xjoyghosh.medium.com/information-gathering-scanning-for-sensitive-information-reloaded- ...

  7. js中的 AOP

    原文 :http://blog.csdn.net/notejs/article/details/8770575 面向切面的编程(AOP)还是有点意思的,可以在不修改原有代码的情况下增加新功能.有一些j ...

  8. JS在项目中用到的AOP, 以及函数节流, 防抖, 事件总线

    1. 项目中在绑定事件的时候总想在触发前,或者触发后做一些统一的判断或逻辑,在c#后端代码里,可以用Attribute, filter等标签特性实现AOP的效果,可是js中没有这种用法,归根到本质还是 ...

  9. 用AOP来让你的JS代码变得更有可维护性吧

    此文已由作者吴佳祥授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 好吧我承认这是篇任务. 最近看到个消息,ES2017已经定稿了,心想,我去,还完全没了解ES2016呢,ES ...

随机推荐

  1. jquery 实现页面拖拽并保存到cookie

    实现的效果就是页面内的图片可拖拽到任意位置,并将所在位置保存.下次打开页面依然可见.本文是作demo用,实际开发中,位置的数据应保存到数据库中. 好了,开始. 1.准备工作. a.jquery(1.7 ...

  2. GB2312转换成UTF-8与utf_8转换成GB2312

    本文转载:http://www.cnblogs.com/jonhson/archive/2010/08/10/1796536.html /// <summary> /// utf_8转换成 ...

  3. [转]Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡出效果)

    http://blog.csdn.net/yanzi1225627/article/details/22439119 众所周知,想要让ImageView旋转的话,可以用setRotation()让其围 ...

  4. 本地如何搭建IPv6环境测试你的APP

    IPv6的简介 IPv4 和 IPv6的区别就是 IP 地址前者是 .(dot)分割,后者是以 :(冒号)分割的(更多详细信息自行搜索). PS:在使用 IPv6 的热点时候,记得手机开 飞行模式 哦 ...

  5. MVVM之View和ViewModel的关联

    概要: 将所有的VM在加载到Application的Static Resource中,然后在View中用标签指定. 实现: 1)采用特性指定要添加到StaticResource中的对象 public  ...

  6. codevs 1170 双栈排序

    /* 好题啊 好题啊 而然还是看了一眼题解啊 有那么一点思路 但是离写出代码还很远 考虑必须分开放倒两个栈里的情况 即存在i<j<k 有 a[k]<a[i]<a[j] 这里RM ...

  7. React组件的生命周期各环节运作流程

    'use strict'; React.createClass({ //1.创建阶段 getDefaultProps:function(){ //在创建类的时候被调用 console.log('get ...

  8. 关于Android4.x系统默认显示方向各种修改

    1.设置属性值 在device.mk文件中加入PRODUCT_PROPERTY_OVERRIDES += \ ro.sf.hwrotation=180 2.设置屏幕默认显示方向 在frameworks ...

  9. sql-从查询结果创建一个永久表

    语法: select x into new_tableName  from ori_tableName 例如: SELECT [site] ,[day] ,[val]/31.4 [val] into ...

  10. List<T>取交集、差集、并集

    1.  取交集 (A和B都有) List A : { 1 , 2 , 3 , 5 , 9 }List B : { 4 , 3 , 9 }var intersectedList = list1.Inte ...