JavaScript实现AOP详解
什么是AOP
AOP(Aspect Oriented Programming),中文译为面向切面编程,是一种编程方法论。它通过预编译方式和运行期动态代理实现程序功能的统一维护的方法。
AOP 解决的问题主要是将那些与业务无关,却为业务模块所共同调用的逻辑或责任进行封装,并分离出来,例如在不修改源代码的情况下统一添加日志记录和权限控制等。
AOP的应用场景
- 日志记录
- 接口请求校验(鉴权)
- 性能统计
- 事务处理
实现方式
AOP的实现方式主要有下面两种:
- 静态AOP
- 动态AOP
在JavaScript中,由于没有编译过程,我们只能使用动态AOP来实现。
动态AOP
动态AOP可以通过vscode插件node-debug2来调试,并实现对方法调用的控制。它的实现方式是将一个函数在运行时动态地加入到对象中。
这个函数可以在原函数调用前、调用后,抑或调用前后都被执行,从而实现AOP。
我们将这些增强一个函数的方法称之为"切面"
看下面的代码:
Function.prototype.before = function(beforeFn){
var self = this; // 保存原函数的引用
return function() { // 返回包含了原函数和新函数的"代理"函数
beforeFn.apply(this, arguments); // 执行新函数,且保证this不被劫持,新函数接受的参数
// 也会被原封不动地传入原函数,新函数在原函数之前执行
return self.apply(this, arguments); // 执行原函数并返回原函数的执行结果,
// 并且保证this不被劫持
}
}
Function.prototype.after=function(afterFn) {
var self = this;
return function(){
var ret = self.apply(this,arguments);
afterFn.apply(this,arguments);
return ret;
}
}
我们在Function.prototype上新增两个方法,before和after。
- before方法:在原函数执行之前执行一个函数。
- after方法:在原函数执行之后执行一个函数。
现在我们定义了一个方法,用于向用户显示订单详情:
function showOrder(order) {
console.log(`订单号: ${order.no}\n名称:${order.name}\n价格:${order.price}\n数量:${order.quantity}\n总价:${order.price * order.quantity}\n`);
}
const order = {
no: '123',
name: '衣服',
price: 100,
quantity: 2
};
showOrder(order);
现在我们想在这个方法执行前输出一行日志,如下:
function log(){
console.log(`[${new Date()}] 启动方法: ${showOrder.name}`);
}
showOrder.before(log);
这样做就可以在showOrder方法执行前输出一行日志了。
我们同样可以在方法执行后输出返回结果的日志:
function log2(ret){
console.log(`[${new Date()}] ${showOrder.name}返回: ${ret}`);
}
showOrder.after(log2);
这样做就可以在showOrder方法执行后输出结果了。
完整代码如下:
Function.prototype.before = function(beforeFn){
var self = this; // 保存原函数的引用
return function() { // 返回包含了原函数和新函数的"代理"函数
beforeFn.apply(this, arguments); // 执行新函数,且保证this不被劫持,新函数接受的参数
// 也会被原封不动地传入原函数,新函数在原函数之前执行
return self.apply(this, arguments); // 执行原函数并返回原函数的执行结果,
// 并且保证this不被劫持
}
}
Function.prototype.after=function(afterFn) {
var self = this;
return function(){
var ret = self.apply(this,arguments);
afterFn.apply(this,arguments);
return ret;
}
}
function showOrder(order) {
console.log(`订单号: ${order.no}\n名称:${order.name}\n价格:${order.price}\n数量:${order.quantity}\n总价:${order.price * order.quantity}\n`);
}
const order = {
no: '123',
name: '衣服',
price: 100,
quantity: 2
};
function log(){
console.log(`[${new Date()}] 启动方法: ${showOrder.name}`);
}
function log2(ret){
console.log(`[${new Date()}] ${showOrder.name}返回: ${ret}`);
}
showOrder.before(log);
showOrder.after(log2);
showOrder(order);
AOP装饰器模式
装饰器模式是指在不改变对象自身的基础上,在程序运行期间来动态修改其功能的方式。
通常,装饰器模式把一个对象嵌套在另一个对象中,以实现对原对象的功能增强。
看下面的代码:
Function.prototype.before = function(beforeFn){
var self = this; // 保存原函数的引用
return function() { // 返回包含了原函数和新函数的"代理"函数
beforeFn.apply(this, arguments); // 执行新函数,且保证this不被劫持,新函数接受的参数
// 也会被原封不动地传入原函数,新函数在原函数之前执行
return self.apply(this, arguments); // 执行原函数并返回原函数的执行结果,
// 并且保证this不被劫持
}
}
Function.prototype.after=function(afterFn) {
var self = this;
return function(){
var ret = self.apply(this,arguments);
afterFn.apply(this,arguments);
return ret;
}
}
class ShowOrder {
show(order) {
console.log(`订单号: ${order.no}\n名称:${order.name}\n价格:${order.price}\n数量:${order.quantity}\n总价:${order.price * order.quantity}\n`);
}
}
const order = {
no: '123',
name: '衣服',
price: 100,
quantity: 2
};
const showOrder = new ShowOrder().show;
function log(){
console.log(`[${new Date()}] 启动方法: ${showOrder.name}`);
}
showOrder = showOrder.before(log);
function log2(ret){
console.log(`[${new Date()}] ${showOrder.name}返回: ${ret}`);
}
showOrder = showOrder.after(log2);
showOrder(order);
通过装饰器模式,我们实现了对某一个对象方法的AOP增强。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript实现AOP详解(面向切面编程,装饰者模式) - Python技术站