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 相关文章推荐
js操作二级联动实现代码
Jul 27 Javascript
File, FileReader 和 Ajax 文件上传实例分析(php)
Apr 27 Javascript
下拉列表select 由左边框移动到右边示例
Dec 04 Javascript
浅谈javascript中自定义模版
Jan 29 Javascript
JavaScript常用脚本汇总(一)
Mar 04 Javascript
js调用百度地图及调用百度地图的搜索功能
Sep 07 Javascript
jquery中封装函数传递当前元素的方法示例
May 05 jQuery
通俗易懂地解释JS中的闭包
Oct 23 Javascript
vue 不使用select实现下拉框功能(推荐)
May 17 Javascript
ES6数组与对象的解构赋值详解
Jun 14 Javascript
JavaScript实现滑动门效果
Jan 18 Javascript
详解jQuery的核心函数和事件处理
Feb 18 jQuery
使用 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学习资源和链接.
2006/12/05 PHP
PHP取得一个类的属性和方法的实现代码
2011/05/22 PHP
分享下页面关键字抓取www.icbase.com站点代码(带asp.net参数的)
2014/01/30 PHP
codeigniter教程之多文件上传使用示例
2014/02/11 PHP
ThinkPHP文件缓存类代码分享
2015/04/22 PHP
Linux平台PHP5.4设置FPM线程数量的方法
2016/11/09 PHP
Javascript代码混淆综合解决方案-Javascript在线混淆器
2006/12/18 Javascript
js textarea自动增高并隐藏滚动条
2009/12/16 Javascript
jquery获取子节点和父节点的示例代码
2013/09/10 Javascript
js页面跳转的常用方法整理
2013/10/18 Javascript
JS连连看源码完美注释版(推荐)
2013/12/09 Javascript
js函数内变量的作用域分析
2015/01/12 Javascript
详解JavaScript节流函数中的Throttle
2016/07/16 Javascript
jQuery实现的简单拖拽功能示例
2016/09/13 Javascript
谈谈JavaScript中浏览器兼容问题的写法小议
2016/12/17 Javascript
js正则表达式验证表单【完整版】
2017/03/06 Javascript
详解Javascript获取缓存和清除缓存API
2017/05/25 Javascript
React Native 通告消息竖向轮播组件的封装
2020/08/25 Javascript
在Vue中使用highCharts绘制3d饼图的方法
2018/02/08 Javascript
在JavaScript中查找字符串中最长单词的三种方法(推荐)
2021/01/18 Javascript
[03:00]DOTA2-DPC中国联赛1月18日Recap集锦
2021/03/11 DOTA
Python中实现结构相似的函数调用方法
2015/03/10 Python
使用Python的Twisted框架编写简单的网络客户端
2015/04/16 Python
Python元组及文件核心对象类型详解
2018/02/11 Python
pip安装python库的方法总结
2019/08/02 Python
python之yield和Generator深入解析
2019/09/18 Python
python提取xml里面的链接源码详解
2019/10/15 Python
Python常用数字处理基本操作汇总
2020/09/10 Python
米兰必去买手店排行榜首位:Antonioli
2016/09/11 全球购物
意大利巧克力店:Chocolate Shop
2019/07/24 全球购物
局域网定义和特性
2016/01/23 面试题
新教师岗前培训方案
2014/06/05 职场文书
公司领导班子对照检查存在问题整改措施
2014/10/02 职场文书
员工给公司的建议书
2019/06/24 职场文书
为什么不建议在go项目中使用init()
2021/04/12 Golang
Windows Server 2022 超融合部署(图文教程)
2022/06/25 Servers