JavaScript实现AOP详解(面向切面编程,装饰者模式)

yizhihongxing

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技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • 验证用户必选CheckBox控件与自定义验证javascript代码

    验证用户必选CheckBox控件与自定义验证javascript代码是网站开发过程中一个很重要的环节,可以有效地提高网站的安全性和用户体验。本文将详细讲解该过程的完整攻略。 一、HTML中定义CheckBox控件 在HTML页面中,我们可以使用<input type=”checkbox”>标签来定义一个CheckBox控件。要实现用户必选的功能,…

    JavaScript 2023年6月10日
    00
  • js cookies实现简单统计访问次数

    下面是详细讲解“js cookies实现简单统计访问次数”的完整攻略: 1. 什么是cookies? Cookie,有时也用复数形式Cookies,指某些网站为了辨别用户身份、进行Session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookies是网站为了维护用户状态而储存在用户本地终端上的数据。 2. 如何利用js实现统计访问次数? 实现网站的…

    JavaScript 2023年6月11日
    00
  • javascript 基础简介 适合新手学习

    JavaScript 基础简介 适合新手学习 JavaScript 是一种广泛应用于编写网页脚本的编程语言。学习 JavaScript 对于新手来说是一项基础工作,本文章为新手介绍 JavaScript 的基础语法、数据类型、流程控制以及实例应用。 JavaScript 基础语法 JavaScript 代码可嵌入 HTML 页面的 \ 标签中。有两种方式,一…

    JavaScript 2023年5月18日
    00
  • JavaScript中的事件循环方式

    JavaScript中的事件循环方式是Web开发中非常重要的一个概念。它决定了JavaScript的执行顺序,是理解异步编程和Promise的重要起点。在本文中,我将逐步介绍JavaScript的事件循环机制。 什么是事件循环 事件循环指的是JavaScript引擎在空闲时,从消息队列中取出一条消息进行处理的过程。在JavaScript中,事件可以是异步操作…

    JavaScript 2023年5月28日
    00
  • Javascript对象字面量的理解

    JavaScript对象字面量是JavaScript中使用最多的对象创建方法之一。它的基本思想是使用花括号括起来的键值对,其中键表示属性名,值表示属性值。使用对象字面量的方式可以很方便地创建对象,如下面的示例所示: var person = { name: ‘John’, // 属性名为name,属性值为’John’ age: 30, // 属性名为age,…

    JavaScript 2023年5月27日
    00
  • JavaScript中对象property的删除方法介绍

    下面是关于JavaScript对象property的删除方法介绍的完整攻略。 删除对象property的方法 在JavaScript中,我们可以使用多种方式来删除对象的property,具体包括以下三种: delete 操作符 Object.defineProperty() 方法 Object.defineProperties() 方法 下面我们将逐一讲解这…

    JavaScript 2023年6月11日
    00
  • 页面实时更新时间的JS实例代码

    一、准备工作 首先,需要在HTML文件头部链接JS代码文件。 <script src="js/time.js"></script> 然后,在页面中需要有div标签用于显示实时更新的时间。 <div id="clock"></div> 二、具体实现 首先,创建一个名为sho…

    JavaScript 2023年5月27日
    00
  • javascript判断chrome浏览器的方法

    识别浏览器是Web开发中很常见的需求之一,JavaScript 判断 Chrome 浏览器的方法也是其中一种常见的操作。在下面的攻略中,我会介绍三种方法来判断 Chrome 浏览器是否正在使用。 方法一:navigator.userAgent 属性 每个浏览器都会在用户代理(user-agent)字符串中包含一些与其自己有关的信息。在 JavaScript …

    JavaScript 2023年6月11日
    00
合作推广
合作推广
分享本页
返回顶部