关于AOP在JS中的实现与应用详解


Posted in Javascript onMay 06, 2019

1.AOP介绍

简介

AOP (面向切面编程),缩写为Aspect Oriented Programming,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是JAVA 中Spring框架的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

主要功能

  • 日志记录
  • 性能统计
  • 安全控制
  • 事务处理
  • 异常处理等等。

主要意图

将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

  注:请慎重的在JS的中使用AOP!因为部分JS的方法是异步的。 

  必要时使用ES7中的async/await/Promise,以保证代码的顺序执行。

2.AOP在JS中的实现原理

js中aop的实现原理主要依靠Function的两个函数:apply和call。

  • apply函数
Function.apply(obj, args);

apply方法能劫持另外一个对象的方法,继承另外一个对象的属性

Function.apply(obj, args)方法能接收两个参数

obj:这个对象将代替Function类里this对象

args:这个是数组,它将作为参数传给Function(args?>arguments)

利用Function.apply()的参数数组化来提升程序的性能

示例:

function dosomething(a,b,c){
 console.log('do something.', a, b, c);
 // 预期结果: do something. see say run
}

let something = ['see', 'say', 'run'];
dosomething.apply(this, something);

call函数

Function.call(obj, arg, arg, ...);1

示例:

function dosomething(a,b,c){
 console.log('do something.', a, b, c);
 // 预期结果: do something. see say run
}

dosomething.call(this, 'see', 'say', 'run');

  推荐:使用apply函数。call函数和apply函数的效果是一样,但是call函数的参数不够灵活,在写法上参数无法灵活伸缩;apply函数,只需要把参数放到数组里即可。apply比call函数更适合在项目实际开发中使用,并且apply比call的性能要好。

3.AOP在JS中的实现

从事过Java Web开发的童鞋,一定用过Spring框架。在Spring的框架中有before(前置通知)、after(后置通知)、around(环绕通知)。

今天我们在JS中实现的这三种通知。

1. before(前置通知)

before函数,用来实现函数的前置通知。在目标函数的前面执行一些前置操作。

// AOP 前置通知函数声明
/**
 * 给方法加入前置切片函数
 * 可以在执行方法之前执行一些操作,
 * 前置切片的返回值为false时,不影响原方法的执行
 * @param func {Function} 被前置执行的函数
 * @return {Function} 加入前置通知的函数
 */
Function.prototype._before = function(func){
 var __self = this;
 return function(){
  func.apply(__self, arguments);
  return __self.apply(__self, arguments);
 }
}

// 代码
function a(){
 console.log('I\'m a');
}

a = a._before(function(){
 console.log('before');
});

a();
// 结果:
// before
// I'm a

2. after(后置通知)

after函数,用来实现函数的后置通知。在目标函数的后面面执行一些后置操作。

// AOP 后置通知函数声明
/**
 * 给方法加入后置切片函数
 * 可以在执行方法之之后执行一些操作
 * 后置切片的返回值为false时,不影响原方法的执行
 * @param func {Function} 被后置执行的函数
 * @return {Function} 加入后置通知的函数
 * @constructor
 */
Function.prototype._after = function(func){
 var __self = this;
 return function(){
  var ret = __self.apply(__self, arguments);
  func.apply(__self, arguments);
  return ret;
 }
}

// 代码
function b(){
 console.log('I\'m b');
}

b = b._after(function(){
 console.log('after');
});

b();
// 结果:
// I'm b
// after

3. around(环绕通知)

在around函数中,引入了一个JoinPoint对象。JoinPoint对象封装了目标函数和目标函数的参数。在调用JoinPoint对象的invoke函数时,会去调用原来的目标函数。在调用invoke时,如果需要改变目标函数的this对象,需要将对象传入到invoke的参数中。around函数,可以在目标函数的前面和后面随意加入逻辑代码,也可以根据条件判断是否执行目标函数。

// AOP 环绕通知函数声明
/**
 * 切入点对象
 * 不允许切入对象多次调用
 * @param obj 对象
 * @param args 参数
 * @constructor
 */
function JoinPoint(obj, args){
 var isapply = false;      // 判断是否执行过目标函数
 var result = null;       // 保存目标函数的执行结果

 this.source = obj;       // 目标函数对象
 this.args = args;       // 目标函数对象传入的参数

 /**
  * 目标函数的代理执行函数
  * 如果被调用过,不能重复调用
  * @return {object} 目标函数的返回结果
  */
 this.invoke = function(thiz){    
  if(isapply){ return; }
  isapply = true;
  result = this.source.apply(thiz || this.source, this.args);
  return result;
 };

 // 获取目标函数执行结果
 this.getResult = function(){
  return result;
 }
}

/**
 * 方法环绕通知
 * 原方法的执行需在环绕通知方法中执行
 * @param func {Function} 环绕通知的函数
 *  程序会往func中传入一个JoinPoint(切入点)对象, 在适当的时机
 *  执行JoinPoint对象的invoke函数,调用目标函数
 * 
 * @return {Function} 切入环绕通知后的函数,
 */
Function.prototype._around = function(func){
 var __self = this;
 return function(){
  var args = [new JoinPoint(__self, arguments)];
  return func.apply(this, args);
 }
}

// 代码

var isAdmin = true;

function c(){
 console.log('show user list');
}

c = c._around(function(joinpoint){
 if(isAdmin){ // 满足条件时,执行目标函数
  console.log('is admin');
  joinpoint.invoke(this);
 }
});

c();
// 结果
// if isAdmin == true
//  is admin
//  show user list
// if isAdmin == false
//

4.AOP在JS中的应用

AOP在数据库方面的应用

  • 记录sql的执行记录(AOP的前置通知)
  • 记录sql的执行时间(AOP的环绕通知)
  • sql执行完后自动释放连接(AOP的环绕通知)

本人基于NodeJS写了一个关系型数据库持久层框架——Ebatis。在Ebatis中,使用了AOP思想,完美解决了对sql执行记录,性能等信息的监控,并且可以自动释放连接。

有兴趣的可以使用我写的Ebatis框架。

Ebatis相当于Java上的Mybatis,像mybatis一样,支持动态sql,支持事务,配置简单。目前只支持Mysql数据库,后续兼容 Postgresql,SqlServer,Sqlite 等其他关系型数据库。

GitHub地址 :https://github.com/muzin/ebatis

或者

Npm地址:https://www.npmjs.com/package/ebatis

或者

npm install ebatis1

后续,加入AOP在JS中的应用的示例代码~~~

就先到这~

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript算法学习(直接插入排序)
Apr 12 Javascript
基于JQuery的列表拖动排序实现代码
Oct 01 Javascript
jQuery实现带滚动导航效果的全屏滚动相册实例
Jun 19 Javascript
js实现Select列表内容自动滚动效果代码
Aug 20 Javascript
JavaScript验证Email(3种方法)
Sep 21 Javascript
表单验证插件Validation应用的实例讲解
Oct 10 Javascript
JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
Dec 02 Javascript
快速掌握jQuery插件WebUploader文件上传
Nov 07 Javascript
JS排序之冒泡排序详解
Apr 08 Javascript
jQuery实现的页面弹幕效果【测试可用】
Aug 17 jQuery
vue+axios+element ui 实现全局loading加载示例
Sep 11 Javascript
原生js+ajax分页组件
Jan 30 Javascript
JS使用iView的Dropdown实现一个右键菜单
May 06 #Javascript
一文读懂ES7中的javascript修饰器
May 06 #Javascript
JavaScript中AOP的实现与应用
May 06 #Javascript
使用 vue 实现灭霸打响指英雄消失的效果附demo
May 06 #Javascript
vue如何截取字符串
May 06 #Javascript
用vscode开发vue应用的方法步骤
May 06 #Javascript
微信小程序合法域名配置方法
May 06 #Javascript
You might like
浅析php变量作用域的一些问题
2013/08/08 PHP
php二维数组排序方法(array_multisort usort)
2013/12/25 PHP
PHP快速按行读取CSV大文件的封装类分享(也适用于其它超大文本文件)
2014/04/10 PHP
PHP整数取余返回负数的相关解决方法
2014/05/15 PHP
PHP页面跳转操作实例分析(header方法)
2016/09/28 PHP
php处理抢购类功能的高并发请求
2018/02/08 PHP
jquery load事件(callback/data)使用方法及注意事项
2013/02/06 Javascript
高效的获取当前元素是父元素的第几个子元素
2013/10/15 Javascript
setTimeout和setInterval的深入理解
2013/11/08 Javascript
js出生日期 年月日级联菜单示例代码
2014/01/10 Javascript
js的[defer]和[async]属性
2014/11/24 Javascript
jQuery显示和隐藏 常用的状态判断方法
2015/01/29 Javascript
Javascript代码实现仿实例化类
2015/04/03 Javascript
使用JQuery实现Ctrl+Enter提交表单的方法
2015/10/22 Javascript
使用angularjs创建简单表格
2016/01/21 Javascript
在Node.js中使用Javascript Generators详解
2016/05/05 Javascript
jQuery+CSS3+Html5实现弹出层效果实例代码(附源码下载)
2016/05/16 Javascript
JQuery DIV 动态隐藏和显示的方法
2016/06/23 Javascript
Bootstrap 模态框(Modal)插件代码解析
2016/12/21 Javascript
微信小程序 登陆流程详细介绍
2017/01/17 Javascript
bootstrap警告框示例代码分享
2017/05/17 Javascript
JavaScript之生成器_动力节点Java学院整理
2017/06/30 Javascript
JavaScript中运算符规则和隐式类型转换示例详解
2017/09/06 Javascript
JavaScript中立即执行函数实例详解
2017/11/04 Javascript
小程序云开发获取不到数据库记录的解决方法
2019/05/18 Javascript
javascript实现雪花飘落效果
2020/08/19 Javascript
Python multiprocessing.Manager介绍和实例(进程间共享数据)
2014/11/21 Python
Python二叉搜索树与双向链表转换算法示例
2019/03/02 Python
numpy下的flatten()函数用法详解
2019/05/27 Python
python登录WeChat 实现自动回复实例详解
2019/05/28 Python
python定义具名元组实例操作
2021/02/28 Python
Superdry极度干燥美国官网:英国制造的服装品牌
2018/11/13 全球购物
新员工入职感言
2014/02/01 职场文书
2014最新自愿离婚协议书范本
2014/11/19 职场文书
详解Python魔法方法之描述符类
2021/05/26 Python
你真的会用Mysql的explain吗
2022/03/31 MySQL