『设计模式』高阶函数实现 AOP

本文介绍了面向切面编程(AOP)的概念及其在JavaScript中的实现方式。AOP是一种程序设计范型,用于分离横切关注点,如日志记录、安全控制等,从而使核心业务逻辑更加纯净和高内聚。文章详细展示了如何通过修改JavaScript函数来实现AOP的思想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一篇记录了自己思考的读书笔记。
博客:Murphy 的博客
知乎:@Murphy

面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、观点导向编程、剖面导向程式设计)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。

从编程的角度看,在运行时,动态地将代码切入到类的指定方法、指定位置的编程思想就是面向切面编程

AOP 的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便地复用日志统计等功能模块。

从主关注点中分离出横切关注点是面向侧面的程序设计(aspect-oriented programming)的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。

在 Java 语言中,可以通过反射和动态代理实现 AOP 技术,而在 JavaScript 中,有一种非常巧妙的方法实现。我们先来看一下想要达到的效果:

原来的函数长这样(可以把它看作核心业务逻辑):

var func = function() {
      console.log(2);
}复制代码

现在呢,想改造一下这个函数,把某些希望在把这个函数之前执行和之后执行的函数“动态织入”到核心函数中,像这样:

func = func.before(function() {
      // 在 func 执行之前执行的函数
}).after(function() {
      // 在 func 执行之后执行的函数
})复制代码

然后再执行

func();复制代码

时,能够依次执行 before() 传入的函数,func() 原来的内容,最后是 after() 传入的函数。怎么做到呢?

首先,函数能够链式执行下去意味着任何函数(或者其原型链上)都有对 beforeafter 的定义,因此可以扩充函数的构造函数(Function) 的原型(prototype)。然后为了能按照我们希望的顺序执行,需要调整 func() 本身的内容在执行过程中的顺序。我们知道在 JavaScript 中,除了直接执行一个函数外,还可以使用 call 或者 apply 执行,比如:

var foo = function(str) {
      console.log(str);
}
foo("hello"); // hello
foo.call(this, "hello"); // hello
foo.apply(this, ["hello"]); // hello复制代码

所以呢,是不是可以这样子,为了在执行核心函数 func 之前动态织入 before 中的函数,可以先保存对 func 的引用,并在之后返回一个规定好执行顺序的装饰后的函数。像这样:

Function.prototype.before = function(beforefn) {
      var _self = this; // 保存对原函数的引用
      return function() {
            beforefn.apply(this, arguments);
            _self.apply(this, arguments);
      }
}复制代码

注意这句 _self = this 的作用,因为我们调用 before 时会作为核心函数的方法调用,所以第一个 this 会是核心函数本身;而在返回的函数中,this 就无所谓了,它指向的是全局变量,在浏览器中的话就是 window

来验证一下:

func = func.before(function() {
    console.log(1);
})

func(); // 1  2复制代码

Success √

所以 after 的写法也类似:

Function.prototype.after = function(afterfn) {
      var _self = this;
      return function() {
            _self.apply(this, arguments);
            afterfn.apply(this, arguments);
      }
}复制代码

还是一样测试一下:

func = func.after(function() {
    console.log(3);
})

func(); // 2  3复制代码

也可以链式调用起来:

func = func.before(function() {
    console.log(1);
}).after(function() {
    console.log(3);
})

func(); // 1  2  3复制代码

这种使用 AOP 的方式来给函数动态的添加职责,也是 JavaScript 语言中一种特别和巧妙的装饰者模式实现。

参考:

JavaScript 设计模式与开发实践

维基百科-面向侧面的程序设计

转载于:https://juejin.im/post/5a0f8c3951882503eb4adba0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值