关于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 相关文章推荐
jQuery MD5加密实现代码
Mar 15 Javascript
3种不同方式的焦点图轮播特效分享
Oct 30 Javascript
jQuery 的全选(全非选)即取得被选中的值使用介绍
Nov 12 Javascript
经过绑定元素时会多次触发mouseover和mouseout事件
Feb 28 Javascript
滚动条响应鼠标滑轮事件实现上下滚动的js代码
Jun 30 Javascript
js实现window.open不被拦截的解决方法汇总
Oct 30 Javascript
JS获得图片alt信息的方法
Apr 01 Javascript
JavaScript对Cookie进行读写操作实例
Jul 25 Javascript
js replace()去除代码中空格的实例
Feb 14 Javascript
基于JavaScript实现移动端无限加载分页
Mar 27 Javascript
JavaScript编程设计模式之构造器模式实例分析
Oct 25 Javascript
vue 清空input标签 中file的值操作
Jul 21 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 jQuery表单,带验证具体实现方法
2014/02/15 PHP
修改destoon会员公司的伪静态中的com目录的方法
2014/08/21 PHP
详解PHP实现定时任务的五种方法
2016/07/25 PHP
php ActiveMQ的安装与使用方法图文教程
2020/02/23 PHP
禁止直接访问php文件代码分享
2020/05/05 PHP
Javascript 面向对象 对象(Object)
2010/05/13 Javascript
JavaScript 计算图片加载数量的代码
2011/01/01 Javascript
数组方法解决JS字符串连接性能问题有争议
2011/01/12 Javascript
基于Jquery实现表格动态分页实现代码
2011/06/21 Javascript
jQuery学习笔记 操作jQuery对象 文档处理
2012/09/19 Javascript
分享一款基于jQuery的视频播放插件
2014/10/09 Javascript
PHP守护进程实例
2015/03/06 Javascript
通过点击jqgrid表格弹出需要的表格数据
2015/12/02 Javascript
学习javascript面向对象 理解javascript对象
2016/01/04 Javascript
jquery实现列表上下移动功能
2016/02/25 Javascript
JS数组搜索之折半搜索实现方法分析
2017/03/27 Javascript
input输入框内容实时监测(附代码)
2017/08/15 Javascript
react-native 完整实现登录功能的示例代码
2017/09/11 Javascript
JavaScript中的一些隐式转换和总结(推荐)
2017/12/22 Javascript
Layui之table中的radio在切换分页时无法记住选中状态的解决方法
2019/09/02 Javascript
Python装饰器原理与用法分析
2018/04/30 Python
Linux下python与C++使用dlib实现人脸检测
2018/06/29 Python
手写一个python迭代器过程详解
2019/08/27 Python
python可以用哪些数据库
2020/06/22 Python
解决TensorFlow训练模型及保存数量限制的问题
2021/03/03 Python
CSS3移动端vw+rem不依赖JS实现响应式布局的方法
2019/01/23 HTML / CSS
Html5大文件断点续传实现方法
2015/12/05 HTML / CSS
介绍一下常见的木马种类
2014/11/15 面试题
当x.equals(y)等于true时,x.hashCode()与y.hashCode()可以不相等,这句话对不对
2015/05/02 面试题
个人自我鉴定怎么写
2013/10/28 职场文书
营销与策划专业毕业生求职信
2013/11/01 职场文书
三年级语文教学反思
2014/02/01 职场文书
寒山寺导游词
2015/02/03 职场文书
借条如何写
2015/05/26 职场文书
汤姆索亚历险记读书笔记
2015/06/29 职场文书
2019最新劳动仲裁申请书!
2019/07/08 职场文书