关于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实现页面打印的三种方法
Mar 05 Javascript
一个js写的日历(代码部分网摘)
Sep 20 Javascript
jQuery EasyUI中对表格进行编辑的实现代码
Jun 10 Javascript
css值转换成数值请抛弃parseInt
Oct 24 Javascript
没有document.getElementByName方法
Aug 19 Javascript
js导出table数据到excel即导出为EXCEL文档的方法
Oct 10 Javascript
Jquery 切换不同图片示例代码
Dec 05 Javascript
在JavaScript中重写jQuery对象的方法实例教程
Aug 25 Javascript
深入理解JavaScript系列(38):设计模式之职责链模式详解
Mar 04 Javascript
javascript引用类型之时间Date和数组Array
Aug 27 Javascript
详解vue通过NGINX部署在子目录或者二级目录实践
Sep 03 Javascript
Javascript实现动态时钟效果
Nov 17 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
《被神捡到的男人》动画化计划进行中!
2020/03/06 日漫
一个图形显示IP的PHP程序代码
2007/10/19 PHP
php压缩HTML函数轻松实现压缩html/js/Css及注意事项
2013/01/27 PHP
改进:论坛UBB代码自动插入方式
2006/12/22 Javascript
一个基于jquery的文本框记数器
2012/09/19 Javascript
JavaScript将Table导出到Excel实现思路及代码
2013/03/13 Javascript
Jquery图片滚动与幻灯片的实例代码
2013/04/08 Javascript
JS调用CS里的带参方法实例
2013/08/01 Javascript
无刷新预览所选择的图片示例代码
2014/04/02 Javascript
jquery实现动态操作select选中
2015/02/11 Javascript
jquery实现浮动在网页右下角的彩票开奖公告窗口代码
2015/09/04 Javascript
原生JS实现仿淘宝网左侧商品分类菜单效果代码
2015/09/10 Javascript
三种Node.js写文件的方式
2016/03/08 Javascript
BootStrap中按钮点击后被禁用按钮的最佳实现方法
2016/09/23 Javascript
基于Bootstrap框架实现图片切换
2017/03/10 Javascript
手写Node静态资源服务器的实现方法
2018/03/20 Javascript
JS实现图片旋转动画效果封装与使用示例
2018/07/09 Javascript
Vue事件修饰符native、self示例详解
2019/07/09 Javascript
微信小程序简单的canvas裁剪图片功能详解
2019/07/12 Javascript
vue.js实现回到顶部动画效果
2019/07/31 Javascript
js实现翻牌小游戏
2020/07/31 Javascript
遗传算法python版
2018/03/19 Python
python如何在循环引用中管理内存
2018/03/20 Python
Python实现word2Vec model过程解析
2019/12/16 Python
django处理select下拉表单实例(从model到前端到post到form)
2020/03/13 Python
python 如何调用 dubbo 接口
2020/09/24 Python
python可视化分析的实现(matplotlib、seaborn、ggplot2)
2021/02/03 Python
css3如何绘制一个圆圆的loading转圈动画
2018/01/09 HTML / CSS
草莓网英国官网:Strawberrynet UK
2017/02/12 全球购物
俄罗斯宠物用品网上商店:ZooMag
2019/12/12 全球购物
大学生自我评价范文分享
2014/02/21 职场文书
调研汇报材料范文
2014/08/17 职场文书
上课说话检讨书500字
2014/11/01 职场文书
2014年教育实习工作总结
2014/11/22 职场文书
JavaScript 与 TypeScript之间的联系
2021/11/27 Javascript
详解MySQL的主键查询为什么这么快
2022/04/03 MySQL