1、背景
面向切面编程(Aspect Oriented Programming,AOP)是一种编程思想,它将程序逻辑分为核心业务逻辑和横切逻辑。横切逻辑是指在不改变原有核心业务逻辑的基础上,插入特定的代码段以实现特定的功能,例如日志记录、性能监控、事务管理等。在传统的面向对象编程中,实现面向切面编程通常需要使用设计模式或者各种织入工具。而在 ES6 中,我们可以使用 Proxy 代理实现更为简单高效的面向切面编程。
2、Proxy 代理的基本用法
Proxy 是 ES6 中新增的代理对象,它可以用来代理另一个对象的行为。Proxy 构造函数接收两个参数:需要代理的对象和一个处理程序(handler)。处理程序是一个包含各种代理行为的对象。Proxy 对象代理着目标对象,我们可以通过 Proxy 对象调用目标对象的属性和方法。
2.1、代理函数调用
我们先来看下 Proxy 代理函数调用的示例:
-- -------------------- ---- ------- ----- ------ - - ---- ---------- - ------ ------ - -- ----- ------- - - ------ ---------------- -------- -------------- - -------------------- - - ----------- - - ---- ----- - - --------------- ------ --------------------- --------------- - -- ----- ----- - --- ----------------- --------- -------------------------- ----------
output:
Calling foo with args: hello,world foo
这个示例中,我们先定义了 target 对象,其中有一个 foo 方法。接下来定义了 handler 处理程序对象,其中包含了我们要捕获的行为 apply,也就是一个函数被调用的行为。在该行为发生时,代理会获取被代理的函数、该函数的 this 指向以及调用参数列表。接着代理打印了一条消息,并且继续调用了原来的函数。
2.2、代理对象的访问行为
接下来我们看下代理对象的访问行为的示例:
-- -------------------- ---- ------- ----- ------ - - ---- -- ---- - -- ----- ------- - - ---- ---------------- --------- --------- - -------------------- - - ---------- ------ ----------------- - -- ----- ----- - --- ------------- --------- ----------------------- -----------------------
output:
Getting foo 1 Getting bar 2
在这个示例中,我们定义了 target 对象,其中包含两个属性 foo 和 bar。然后定义了 handler 处理程序对象,其中包含了我们要捕获的行为 get,也就是一个属性被访问时的行为。在该行为发生时,代理会获取被代理的对象、访问的属性名以及访问操作所在的对象。接着代理打印了一条消息,并且返回了被代理对象的属性值。
3、利用 Proxy 实现面向切面编程
在上面的两个示例中,我们了解了 Proxy 的基本用法。接下来,我们结合这些基本用法,看下如何使用 Proxy 实现面向切面编程。
3.1、日志记录
我们先来看下如何使用 Proxy 实现日志记录:
-- -------------------- ---- ------- -------- ----------- - ------ --- ------------- - ------ ---------------- -------- -------------- - ------------------- ------------------------- ------- -------- ---------------- ---- ----- -- --------------- ------ --------------------- --------------- - --- - ----- --- - --- -- -- - - -- ----- --------- - --------- ------------------------ ---- ------------------------ ----
output:
[6/5/2022, 6:32:02 PM] Calling function "add" with args: [ 1, 2 ] 3 [6/5/2022, 6:32:02 PM] Calling function "add" with args: [ 3, 4 ] 7
在这个示例中,我们首先定义了一个 log 函数,它接收需要被代理的函数作为参数。然后我们使用 Proxy 将被代理函数重写,并在代理函数的 apply 行为触发时添加了日志记录功能。接着我们定义了一个 add 函数,并将 add 函数代理给 proxyFunc。最后输出了对 proxyFunc 的两次调用。在每次调用时,代理函数都会输出一条日志记录。
3.2、性能监控
下面我们看下如何使用 Proxy 实现性能监控:
-- -------------------- ---- ------- -------- ------------ - ------ --- ------------- - ------ ---------------- -------- -------------- - ----- ----- - ----------- ----- ------ - --------------------- --------------- ----- --- - ----------- --------------------- ---------------- ---- ------ - ------ - ----- -- ---------- ------ ------- - --- - ----- --------- - --- -- - -- -- --- - -- - --- -- - ------ -- - ------ ----------- - -- - ----------- - --- -- ----- --------- - ---------------- ---------------------------
output:
Function "fibonacci" took 97.8ms to execute 832040
在这个示例中,我们首先定义了一个 time 函数,它接收需要被代理的函数作为参数。然后我们使用 Proxy 将被代理函数重写,并在代理函数的 apply 行为触发时添加了性能监控功能。在代理函数的执行前记录下时间戳,执行结束后再记录下时间戳,最后计算出时间差并输出性能日志。
3.3、钩子函数
最后我们看下如何使用 Proxy 实现钩子函数。钩子函数是在原函数执行前或执行后执行的函数,它可以用来实现诸如权限校验、参数预处理等功能。
-- -------------------- ---- ------- -------- ------------ - ------ --- ------------- - ------ ---------------- -------- -------------- - ------------------- ------- --------------------- --------------- ------------------ ------- - --- - ----- ----- - --------- -- --------------------- ----- --------- - ------------ ----------------- ---------
output:
Before hook Hello, world! After hook
在这个示例中,我们首先定义了一个 hook 函数,它接收需要被代理的函数作为参数。然后我们使用 Proxy 将被代理函数重写,并在代理函数的 apply 行为触发时添加了钩子函数功能。在代理函数的执行前输出 Before hook,在执行后输出 After hook。
4、总结
本文介绍了 ES6 中的 Proxy 代理,并结合示例讲解了如何使用 Proxy 实现面向切面编程。使用 Proxy 可以使得面向切面编程的实现更为简洁高效,并且相比传统的面向对象编程方式,不需要使用设计模式或复杂的织入工具。我们通过日志记录、性能监控和钩子函数这些示例验证了 Proxy 的使用和效果,期望大家能够在实际项目中灵活应用,并在开发实践中发现更多的优雅实现方式。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6493e11648841e9894175711