面向切面编程,我对它的简单理解为:为了能通用的在函数前后执行某些操作。虽然目前AOP对JavaScript并不是热门话题,但是JavaScript一些新特性已经开始运用这一思想了。
为了能通用的在函数前后执行某些操作
function test(arg1) {
console.log(2);
return arg1;
}
假设当前有一个 test 函数,我们需要测试 test 函数执行时消耗的时间,那么最先想到的做法是:
var start = new Date();
test("a");
var end = new Date();
console.log('spend:' + (end - start));
但如果需要测试更多的函数,我们就需要编写更多的 start、end,为了能通用的在函数前后执行某些操作,我们尝试引用面向切面编程(AOP):
Function.prototype.before = function(fn){
var __test = this;
return function beforeClosure() {
fn();
return __test.apply(this, arguments);
}
}
Function.prototype.after = function(fn){
var __beforeClosure = this;
return function afterClosure() {
var result = __beforeClosure.apply(this, arguments);
fn();
return result;
}
}
最后测试代码test被改为:
var start = 0
var end = 0
function startTime(){
start = new Date()
}
function endTime(){
end = new Date()
console.log('speed: '+ (end - start))
}
test.before(startTime).after(endTime)('c')
严格模式下
"use strict"
Function.prototype.before = function(fn){
return (function(){
fn()
return this
}.bind(this))()
}
Function.prototype.after = function(fn){
return (function(){
var result = this
fn()
return result
}.bind(this))()
}
// 使用
func.before(fn).after(fn)(args)
用AOP实现职责链
将after函数改写,使得第一个函数返回‘nextSuccessor’时,将请求继续传递给下一个函数。这里的字符串‘nextSuccessor’只是一种自定义的状态,为了更好表达前一步骤是否满足条件。
具体案例请移步《JavaScript设计模式与开发实践》一书中的职责链模式p.186
用AOP来实现职责链既简单又巧妙,但这种把函数叠在一起的方式,同时也叠加来函数的作用域,如果链条太长的话,也会对性能有较大的影响。
Function.prototype.after = function(fn){
var self = this;
return function(){
var ret = self.apply(this, arguments);
if(ref === 'nextSuccessor'){
return fn.apply(this,arguments)
}
return ref;
}
}
var order = order500yuan.after( order200yuan ).afte( orderNormal )
装饰器模式
装饰器模式(Decorators)是一个典型的AOP应用。装饰器基本原理如下:
@decorator
class A{}
// 相当于
class A{}
A = decorator(A) || A
因此对第一节进行改造
function before(fn) {
fn();
return function(target, key, desc){}
}
@before(function(){start = new Date()})
class MyTestableClass {
constructor(fn){
fn()
}
after(fn){
fn();
return this
}
}
var start,end;
new MyTestableClass(function(){
// do something
}).after(function(){end = new Date})
参考
- [1] 简书-rayman_v. javascript 面向切面编程(AOP)
- [2] 简书-Binaryify. JavaScript面向切面编程
- [3] JavaScript设计模式与开发实践 [M] p.186
- [4] medium.com - Proxy + Decorator如何实现Javascript中的AOP
- [5] medium.com - React-redux 的 connect 之装饰器实现
网友评论