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

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日

相关文章

  • Javascript中判断一个值是否为undefined的方法详解

    当我们使用JavaScript编写代码时,通常需要对变量或函数返回值是否为“未定义(undefined)”进行判断,JavaScript中判断一个值是否为undefined的方法有很多种,下面我们就逐个进行说明。 1.使用typeof typeof是用来检测变量类型的操作符,如果变量未定义,则返回”undefined”,因此可以用typeof来判断一个值是否…

    JavaScript 2023年5月28日
    00
  • JS验证日期的格式YYYY-mm-dd 具体实现

    JS验证日期的格式可以使用正则表达式来完成。代码实现如下: // 定义正则表达式 var reg = /^(\d{4})-(\d{2})-(\d{2})$/; // 验证日期格式 function verifyDate(dateStr) { if (reg.test(dateStr)) { return true; } else { return false…

    JavaScript 2023年5月27日
    00
  • JavaScript流程控制(循环)

    JavaScript流程控制(循环) JavaScript提供了循环结构来重复执行代码块,为开发者处理重复性任务提供了方便。 在JavaScript中,有三种循环结构:for、while和do…while。在使用这些结构之前需要确定循环的条件,即循环的终止条件。只有当终止条件为false时,循环才会停止。 1. for循环 for循环是JavaScrip…

    JavaScript 2023年5月27日
    00
  • 详解cesium实现大批量POI点位聚合渲染优化方案

    详解cesium实现大批量POI点位聚合渲染优化方案 概述 随着互联网和移动设备的普及,地理信息系统(GIS)以及地理数据的使用越来越广泛。在GIS应用开发中,矢量数据展示常常使用散点图,而在数据量较大的情况下,需要对散点进行聚合来达到优化效果。在本文中,我们将详细介绍如何使用cesium实现大批量POI点位聚合渲染优化方案。 cesium点位聚合原理 常见…

    JavaScript 2023年6月11日
    00
  • arcgis js完整悬停效果实现demo

    悬停效果实现原理 在实现悬停效果之前,我们需要先了解一下悬停效果的原理。悬停效果可以通过两种方式来实现,即CSS方式和JavaScript方式。其中,CSS方式仅能实现简单的悬停效果,而JavaScript方式能实现复杂的个性化悬停效果。 在arcgis js中,我们使用JavaScript方式来实现悬停效果。具体实现步骤如下: (1)通过添加事件监听器(如…

    JavaScript 2023年6月11日
    00
  • 学习javascript面向对象 掌握创建对象的9种方式

    学习JavaScript面向对象是Web开发中非常重要的一块,能够帮助我们更好的组织和管理JavaScript代码,实现更好的代码复用和模块化开发。在JavaScript中,我们可以使用多种方式来创建对象,本篇攻略将详细介绍9种创建对象的方式,以便大家更好地掌握JavaScript面向对象编程。 1. Object方式 通过Object方式创建对象是最基础的…

    JavaScript 2023年5月27日
    00
  • JS中的回调函数实例浅析

    JS中的回调函数实例浅析 什么是回调函数 回调函数是一种在函数执行完毕后,将另一个函数作为参数传递给它,并在后者执行的函数。它的特点是:回调函数是作为参数传递给另一个函数的,当另一个函数执行完毕后,回调函数才会被执行。 回调函数通常用于异步编程中,由于JavaScript是单线程的,异步调用的函数执行完毕后需要得到回调函数的执行结果,以便继续执行后续的代码。…

    JavaScript 2023年5月28日
    00
  • JavaScript创建一个欢迎cookie弹出窗实现代码

    下面是JavaScript创建一个欢迎cookie弹出窗实现的代码攻略。 1. 设计思路 首先,我们需要确认弹出窗的内容、样式、位置等,然后创建一个模态框来实现弹出窗。考虑到欢迎弹出窗的出现与用户的cookie状态有关,我们还需要使用cookie以及相关的JS库来实现。 具体的设计思路如下: 确认欢迎弹出窗的内容、样式和位置 判断用户的cookie状态,若未…

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