关于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 相关文章推荐
document 和 document.all 分别什么时候用
Jun 22 Javascript
JavaScript 常见对象类创建代码与优缺点分析
Dec 07 Javascript
jquery 弹出登录窗口实现代码
Dec 24 Javascript
JS实现动态给图片添加边框的方法
Apr 01 Javascript
微信小程序之小豆瓣图书实例
Nov 30 Javascript
HTML5 js实现拖拉上传文件功能
Nov 20 Javascript
深入理解JavaScript中的for循环
Feb 07 Javascript
基于Vue实现timepicker
Apr 25 Javascript
深入理解vue $refs的基本用法
Jul 13 Javascript
小程序兼容安卓和IOS数据处理问题及坑
Sep 18 Javascript
简单了解Vue + ElementUI后台管理模板
Apr 07 Javascript
vue-cli3项目配置eslint代码规范的完整步骤
Sep 10 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
一个用于MySQL的PHP XML类
2006/10/09 PHP
桌面中心(四)数据显示
2006/10/09 PHP
php微信公众号开发之校园图书馆
2018/10/20 PHP
JS 模态对话框和非模态对话框操作技巧汇总
2013/04/15 Javascript
javascript的document.referrer浏览器支持、失效情况总结
2014/07/18 Javascript
浅谈javascript实现八大排序
2015/04/27 Javascript
avalonjs实现仿微博的图片拖动特效
2015/05/06 Javascript
网页收藏夹显示ICO图标(代码少)
2015/08/04 Javascript
基于jquery实现鼠标滚轮驱动的图片切换效果
2015/10/26 Javascript
理解nodejs的stream和pipe机制的原理和实现
2017/08/12 NodeJs
详解react-native-fs插件的使用以及遇到的坑
2017/09/12 Javascript
基于Particles.js制作超炫粒子动态背景效果(仿知乎)
2017/09/13 Javascript
解决ie img标签内存泄漏的问题
2017/10/13 Javascript
JavaScript中的一些隐式转换和总结(推荐)
2017/12/22 Javascript
Vue.js更改调试地址端口号的实例
2018/09/19 Javascript
小程序开发中如何使用async-await并封装公共异步请求的方法
2019/01/20 Javascript
微信小程序按钮点击跳转页面详解
2019/05/06 Javascript
简单了解vue中的v-if和v-show的区别
2019/10/08 Javascript
详解vue中v-on事件监听指令的基本用法
2020/07/22 Javascript
编写Python脚本来实现最简单的FTP下载的教程
2015/05/04 Python
不同版本中Python matplotlib.pyplot.draw()界面绘制异常问题的解决
2017/09/24 Python
python 平衡二叉树实现代码示例
2018/07/07 Python
Python实现基于POS算法的区块链
2018/08/07 Python
Python爬虫简单运用爬取代理IP的实现
2020/12/01 Python
深入浅析HTML5中的SVG
2015/11/27 HTML / CSS
全球速卖通巴西站点:Aliexpress巴西
2016/08/24 全球购物
体育教育毕业生自荐信
2013/11/21 职场文书
二手书店创业计划书
2014/01/16 职场文书
酒店秘书求职信范文
2014/02/17 职场文书
廉洁自律演讲稿
2014/05/22 职场文书
酒店总经理岗位职责范本
2014/08/08 职场文书
党的群众路线查摆剖析材料
2014/10/10 职场文书
青年岗位能手事迹材料(2016推荐版)
2016/03/01 职场文书
大学毕业生自我鉴定范文
2019/06/21 职场文书
Rust 连接 PostgreSQL 数据库的详细过程
2022/01/22 PostgreSQL
动画电影《龙珠超 超级英雄》延期上映
2022/03/20 日漫