关于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 相关文章推荐
可以把编码转换成 gb2312编码lib.UTF8toGB2312.js
Aug 21 Javascript
jQuery简易图片放大特效示例代码
Jun 09 Javascript
input标签内容改变的触发事件介绍
Jun 18 Javascript
js构造函数、索引数组和属性的实现方式和使用
Nov 16 Javascript
jQuery中triggerHandler()方法用法实例
Jan 19 Javascript
javascript超过容器后显示省略号效果的方法(兼容一行或者多行)
Jul 14 Javascript
Bootstrap基本组件学习笔记之缩略图(13)
Dec 08 Javascript
Websocket协议详解及简单实例代码
Dec 12 Javascript
vue父子组件的数据传递示例
Mar 07 Javascript
解决vue 更改计算属性后select选中值不更改的问题
Mar 02 Javascript
angularjs1.5 组件内用函数向外传值的实例
Sep 30 Javascript
浅谈TypeScript的类型保护机制
Feb 23 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 arsort 数组降序排序详细介绍
2016/11/17 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
2020/02/11 PHP
js活用事件触发对象动作
2008/08/10 Javascript
在html页面中包含共享页面的方法
2008/10/24 Javascript
jquery Firefox3.5中操作select的问题
2009/07/10 Javascript
基于JavaScript实现继承机制之构造函数+原型链混合方式的使用详解
2013/05/07 Javascript
JS小游戏之仙剑翻牌源码详解
2014/09/25 Javascript
javascript常用函数(1)
2015/11/04 Javascript
值得分享的Bootstrap Table使用教程
2016/11/23 Javascript
jQuery插件HighCharts实现的2D面积图效果示例【附demo源码下载】
2017/03/15 Javascript
Node.js中看JavaScript的引用
2017/04/22 Javascript
Express + Node.js实现登录拦截器的实例代码
2017/07/01 Javascript
js实现网页的两个input标签内的数值加减(示例代码)
2017/08/15 Javascript
vue init失败简单解决方法(终极版)
2017/12/22 Javascript
JavaScript事件对象event用法分析
2018/07/27 Javascript
vue.js中proxyTable 转发请求的实现方法
2018/09/20 Javascript
vue实现文字横向无缝走马灯组件效果的实例代码
2019/04/09 Javascript
微信小程序 网络通信实现详解
2019/07/23 Javascript
Vue通过Blob对象实现导出Excel功能示例代码
2020/07/31 Javascript
python处理PHP数组文本文件实例
2014/09/18 Python
Python中在for循环中嵌套使用if和else语句的技巧
2016/06/20 Python
python修改字典键(key)的方法
2019/08/05 Python
python 多进程共享全局变量之Manager()详解
2019/08/15 Python
Pytorch 解决自定义子Module .cuda() tensor失败的问题
2020/06/23 Python
美国著名的品牌折扣店:Burlington
2017/06/08 全球购物
一些Unix笔试题和面试题
2012/09/25 面试题
请问软件开发中的设计模式你会使用哪些
2015/05/13 面试题
应届大学毕业生找工作的求职信范文
2013/11/29 职场文书
运动会邀请函范文
2014/01/31 职场文书
计算机科学系职业生涯规划书
2014/03/08 职场文书
业务员自荐信范文
2014/04/20 职场文书
论文评语大全
2014/04/29 职场文书
幸福中国演讲稿
2014/09/12 职场文书
小学语文继续教育研修日志
2015/11/13 职场文书
班级班风口号大全
2015/12/25 职场文书
Oracle设置DB、监听和EM开机启动的方法
2021/04/25 Oracle