JavaScript中AOP的实现与应用


Posted in Javascript onMay 06, 2019

1. 简介

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

JavaScript中AOP的实现与应用

2. 基础实现

使用过java spring的同学一定知道,其内分为三种通知,before(前置通知)、after(后置通知)、around(环绕通知)。
下面我们分别在js调用方法时实现这三种通知:

before(前置通知)

顾名思义,就是在函数调用前执行

Function.prototype.before = function (beforefun) {
 var _orgin = this; // 保存原函数引用
 return function () { // 返回包含了原函数和新函数的"代理函数"
 beforefun.apply(this, arguments); // 执行新函数,修正this
 return _orgin.apply(this, arguments); // 执行原函数
 }
};

var originFun = function(val){
 console.log('原型函数: '+val);
}

var newFun = originFun.before(function(){
 // 传入函数调用前处理方法
 console.log('before: ' + new Date().getTime())
})

newFun("测试前置通知");

// 调用结果
// before: 1557047939699
// 原型函数: 测试前置通知

after(后置通知)

与before正相反,在函数调用后执行

Function.prototype.after = function (afterfun) {
 var _orgin = this; // 保存原函数引用
 return function () { // 返回包含了原函数和新函数的"代理函数"
 var ret = _orgin.apply(this, arguments); // 执行原函数
 afterfun.apply(this, arguments); // 执行新函数,修正this
 return ret;
 }
};

var originFun = function(val){
 console.log('原型函数: '+val);
}

var newFun = originFun.after(function(){
 // 传入函数调用前处理方法
 console.log('after: ' + new Date().getTime())
})

newFun("测试后置通知");

// 调用结果
// 原型函数: 测试前置通知
// after: 1557047997647

around(环绕通知)

在方法执行前后分别执行

// 利用前面的before、after方法实现
Function.prototype.around = function(beforeFun, afterFun) {
	var _orgin = this;
	return function() {
		return _orgin.before(beforeFun).after(afterFun).apply(this, arguments);
	}
}

3. AOP遇到修饰器

JS在ES7的提案中终于增加了修饰器(Decorator)函数,它是用来修改类的行为,但是现在浏览器都不支持,需要使用Babel进行转换,当AOP与修饰器结合后,又会给我们带来什么呢?

日志记录

通过AOP与修饰器的结合会很方便的进行日志的记录或者函数执行时间的记录

class Person {
 @log
 say(nick) {
 return `hi ${nick}`;
 }
}

function log(target, name, decriptor){
 var _origin = descriptor.value;
 descriptor.value = function(){
 console.log(`Calling ${name} with `, argumants);
 return _origin.apply(null, arguments);
 };

 return descriptor;
}

var person = new Person();
person.say('小明');

判断用户登录状态

class User {
 @checkLogin
 getUserInfo() {
 console.log('获取用户信息')
 }
}

// 检查用户是否登录
function checkLogin(target, name, descriptor) {
 let method = descriptor.value
 descriptor.value = function (...args) {
 // 校验方法,假设这里可以获取到用户名/密码
 if (validate(args)) {
 method.apply(this, args)
 } else {
 console.log('没有登录,即将跳转到登录页面...')
 }
 }
}

let user = new User()
user.getUserInfo()

4. React中的AOP

在react中使用AOP思想的典型就是高阶组件(HOC),请看下面的例子

function HOCComp(WrappedComponent){
 return class HOC extends Component {
 render(){
 const newProps = {param: 'HOC'};
 return <div>
 <WrappedComponent {...this.props} {...newProps}/>
 </div>
 }
 }
}

@HOCComp
class OriginComponent extends Component {
 render(){
 return <div>这是原始组件{this.props.param}</div>
 }
}

上面例子中在HOCComp中定义新的props,并传入子组件中。我们也可以对OriginComponent组件中的一些props进行加工,或对OriginComponent外层进行再次包装。从而不必去修改内部组件,保持了功能上的解耦。

5. 总结

AOP思想在框架及项目中使用的很多,包括React高阶组件、日志记录、登录验证、redux中间件等。在开发中应该与OOP相辅相成,共同提高软件的健壮性及可维护性。

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

参考资料

  • https://3water.com/article/160748.htm
  • https://3water.com/article/160753.htm
Javascript 相关文章推荐
基于JQuery的Select选择框的华丽变身
Aug 23 Javascript
dwz 如何去掉ajaxloading具体代码
May 22 Javascript
js如何获取兄弟、父类等节点
Jan 06 Javascript
简述Jquery与DOM对象
Jul 10 Javascript
用JavaScript判断CSS浏览器类型前缀的两种方法
Oct 08 Javascript
学习JavaScript设计模式(多态)
Nov 25 Javascript
Centos7 中安装 Node.js v4.4.4
Nov 03 Javascript
js实现点击按钮弹出上传文件的窗口
Dec 23 Javascript
AngularJS路由实现页面跳转实例
Mar 03 Javascript
一个简易的js图片轮播效果
Jul 22 Javascript
vue 列表页跳转详情页获取id以及详情页通过id获取数据
Mar 27 Javascript
js+html实现点名系统功能
Nov 05 Javascript
使用 vue 实现灭霸打响指英雄消失的效果附demo
May 06 #Javascript
vue如何截取字符串
May 06 #Javascript
用vscode开发vue应用的方法步骤
May 06 #Javascript
微信小程序合法域名配置方法
May 06 #Javascript
手把手教你使用TypeScript开发Node.js应用
May 06 #Javascript
微信小程序上线发布流程图文详解
May 06 #Javascript
ES6的解构赋值实例详解
May 06 #Javascript
You might like
php开发过程中关于继承的使用方法分享
2011/06/17 PHP
php设计模式 Builder(建造者模式)
2011/06/26 PHP
关于PHP session 存储方式的详细介绍
2013/06/25 PHP
PHP字符串长度计算 - strlen()函数使用介绍
2013/10/15 PHP
深入理解PHP变量的值类型和引用类型
2015/10/21 PHP
关于scrollLeft,scrollTop的浏览器兼容性测试
2013/03/19 Javascript
Jquery通过Ajax访问XML数据的小例子
2013/11/18 Javascript
JavaScript strike方法入门实例(给字符串加上删除线)
2014/10/17 Javascript
jquery提示效果实例分析
2014/11/25 Javascript
jQuery中parent()方法用法实例
2015/01/07 Javascript
JS实现为表格动态添加标题的方法
2015/03/31 Javascript
javascript中indexOf技术详解
2015/05/07 Javascript
Summernote实现图片上传功能的简单方法
2016/07/11 Javascript
JS拉起或下载app的实现代码
2017/02/22 Javascript
Vue.js在使用中的一些注意知识点
2017/04/29 Javascript
浅析webpack 如何优雅的使用tree-shaking(摇树优化)
2017/08/16 Javascript
javascript实现数字配对游戏的实例讲解
2017/12/14 Javascript
详解angular应用容器化部署
2018/08/14 Javascript
element-ui 中的table的列隐藏问题解决
2018/08/24 Javascript
深入浅析Vue.js 中的 v-for 列表渲染指令
2018/11/19 Javascript
layui监听工具栏的实例(操作列表按钮)
2019/09/10 Javascript
js实现轮播图效果 纯js实现图片自动切换
2020/08/09 Javascript
python使用fileinput模块实现逐行读取文件的方法
2015/04/29 Python
python类和函数中使用静态变量的方法
2015/05/09 Python
Python通过poll实现异步IO的方法
2015/06/04 Python
Python简单实现enum功能的方法
2016/04/25 Python
Python中的__slots__示例详解
2017/07/06 Python
Django上使用数据可视化利器Bokeh解析
2019/07/31 Python
python用requests实现http请求代码实例
2019/10/31 Python
python Cartopy的基础使用详解
2020/11/01 Python
css3 transform 3d 使用css3创建动态3d立方体(html5实践)
2013/01/06 HTML / CSS
amazeui树节点自动展开折叠面板并选中第一个树节点的实现
2020/08/24 HTML / CSS
德国孕妇装和婴童服装网上商店:bellybutton
2018/04/12 全球购物
我们的节日春节活动方案
2014/08/22 职场文书
市级绿色学校申报材料
2014/08/25 职场文书
Python实现查询剪贴板自动匹配信息的思路详解
2021/07/09 Python