一个 js 版的 aop 库, 能够无入侵的增加和改变函数或方法的行为.
在函数/方法执行的特定时机执行指定的逻辑. 主要有以下几个类型的通知:
- before: 在函数/方法执行前调用指定逻辑
- after: 在函数/方法执行后调用指定逻辑, 无论函数/方法是否执行成功
- afterReturning: 在函数/方法执行成功后调用指定逻辑
- afterThrowing: 在方法抛出异常后调用指定逻辑
- around: 在函数/方法调用之前和调用之后执行自定义的指定逻辑
切点(连接点筛选)功能, 为 string, RegExp, Function 三个类型之一, 指定符合匹配条件的方法才应用特定的通知逻辑
切面是通知和切点的结合, 通知和切点共同定义了切面的全部内容 - 是什么, 在何时和何处完成功能.
Advisor={// 切点/匹配器, 为字符串,正则,函数三种, 见 PointCut/Matchermatcher: Matcher,// 通知对象, 拥有 before, afterReturning, afterThrowing, after, around 中一个或多个方法advices: {before(...args){/* ... */},after(){/* ... */},afterReturning(returnValue){/* ... */},afterThrowing(){/* ... */},around(joinPoint){/* ... */}}}node
npm install uaopBrowser global
<scriptsrc="path/uaop/dist/bundle.js"></script>模块环境
import*asaopfrom'uaop';// es6// var aop = require('uaop'); // AMD/CMD// window.uaop // globalimport*asaopfrom'uaop';// es6functiondoSomething(){console.log('doSomething');}functionbeforeAdvice{console.log('before doSomething');}// 函数拦截letproxyFunc=aop.before(doSomething,beforeAdvice);proxyFunc();// 对象拦截letobj={doSomething};letproxyObj=aop.before(obj,'doSomething',beforeAdvice);proxyObj.doSomething();// 类拦截classDo{doSomething(){console.log('doSomething');}}letProxyClass=aop.before(Do,'doSomething',beforeAdvice);letinstance=newProxyClass();instance.doSomething();提供针对函数执行拦截的API
返回一个新的函数, 执行逻辑为, 在 functionToAdvise 函数执行前, 执行 beforeFunction, beforeFunction 接收与 functionToAdvise 一致的参数
除非抛异常, 否则不会中断函数的执行
varfunctionToAdvise=function(){console.log('functionToAdvise exec');};varadvisedFunction=aop.before(functionToAdvise,function(){console.log('arguments length:',argument.length);});// log:// arguments length: 3// functionToAdvise execadvisedFunction(1,2,3);返回一个新的函数, 执行逻辑为, 在 functionToAdvise 函数正常返回后, 执行 afterReturningFunction, afterReturningFunction 接收 functionToAdvise 执行后的返回结果作为唯一参数, 不影响返回结果.
varfunctionToAdvise=function(){console.log('functionToAdvise exec');return'functionToAdvise';};varadvisedFunction=aop.afterReturning(functionToAdvise,function(returnValue){console.log('return value: ',returnValue);});// log:// functionToAdvise exec// return value: functionToAdviseadvisedFunction();返回一个新的函数, 执行逻辑为, 在 functionToAdvise 函数抛出异常时, 执行 afterThrowingFunction, afterThrowingFunction 接收 functionToAdvise 抛出的异常对象作为唯一参数.
通知不会吞噬原有异常, 会在 afterThrowingFunction 执行完毕后, 抛出原有异常
varfunctionToAdvise=function(throwError){console.log('functionToAdvise exec');if(throwError){thrownewError('functionToAdvise error');}};varadvisedFunction=aop.afterThrowing(functionToAdvise,function(e){console.log('execption: ',e.message);});// log:// functionToAdvise execadvisedFunction();// log:// functionToAdvise exec// execption: functionToAdvise erroradvisedFunction(true);返回一个新的函数, 执行逻辑为, 在 functionToAdvise 函数正常返回或抛出异常时, 执行 afterFunction
通知不会吞噬原有异常, 会在 afterFunction 执行完毕后, 抛出原有异常
varfunctionToAdvise=function(throwError){if(throwError){console.log('functionToAdvise exception');thrownewError('error');}console.log('functionToAdvise normal exec');};varadvisedFunction=aop.after(functionToAdvise,function(){console.log('after functionToAdvise');});// log:// functionToAdvise normal exec// after functionToAdviseadvisedFunction();// log:// functionToAdvise exception// after functionToAdviseadvisedFunction(true);返回一个新的函数, 执行逻辑为, 执行 aroundFunction, aroundFunction 接收一个 ProceedingJoinPoint 对象作为参数, 调用其 proceed/proceedApply 方法将执行 functionToAdvise.
varfunctionToAdvise=function(){console.log('functionToAdvise exec arguments: ',[].slice.call(arguments,0));return'functionToAdvise return value';};varadvisedFunction=aop.around(functionToAdvise,function(joinPoint){console.log('before functionToAdvise exec');// proceed/proceddApply 可以多次调用, 会多次执行原函数, proceedApply 可以改变 this 和参数信息varresult=joinPoint.proceed();result=joinPoint.proceedApply(null,[1,2]);console.log('functionToAdvise exec result: ',result);console.log('after functionToAdvise exec');});// log:// before functionToAdvise exec// functionToAdvise exec arguments: 1,2,3// functionToAdvise exec arguments: 1,2// functionToAdvise exec result: functionToAdvise return value// after functionToAdvise execadvisedFunction(1,2,3);joinPoint={// 函数被调用时的上下文target: Object,// 传给外层函数的参数args: Array,// 原方法名或函数名method: string,// 被调用时, 会调用被拦截的原函数, 并传入原始参数proceed: Function,// 被调用时, 会调用被拦截的原函数, 首个参数为被拦截函数要执行时的上下文, 第二个参数为要传递给被拦截函数的参数数组proceedApply: Function}创建一个组装了多个通知行为的函数代理, advices 为拥有 before, afterReturning, afterThrowing, after, around 中一个或多个方法的对象.
提供针对对象方法的拦截。
每个拦截接口都接收三个参数:被拦截对象,方法匹配规则 matcher,通知执行函数。
matcher 可为 string, RegExp, Function 的任意一种,为 Function 时,接收被拦截对象和当前方法名作为参数,执行结果返回 true 时,匹配成功,会对该方法执行拦截。
每个拦截接口都会返回一个原对象的代理对象,代理对象会针对符合匹配规则的方法封装,根据通知类型,在方法执行的不同阶段,执行相关的通知逻辑。
注:原对象不受任何影响
返回一个新的代理对象, 在 matcher 匹配的方法执行前,会执行 beforeFunction,beforeFunction 接收匹配方法执行时的参数
除非抛异常, 否则不会中断匹配方法的执行
vartoAdvise={method: function(){console.log('method exec');}};varadvisedObject=aop.before(toAdvise,'method',function(arg){console.log('before method exec');console.log(arg);});// log:// before method exec// a// method execadvisedObject.method('a');// log:// method exectoAdvise.method('a');返回一个新的代理对象, 在 matcher 匹配的方法正常执行后, 执行 afterReturningFunction, afterReturningFunction 接收匹配方法执行后的返回结果作为唯一参数, 不影响返回结果.
vartoAdvise={method: function(){console.log('method exec');return'toAdivse method result';}};varadvisedObject=aop.afterReturning(toAdvise,'method',function(returnValue){console.log('return value: ',returnValue);});// log:// method exec// return value: toAdivse method resultadvisedObject.method();返回一个新的代理对象, 在 matcher 匹配的方法抛出异常后, 执行 afterThrowingFunction, afterThrowingFunction 接收匹配方法抛出的异常对象作为唯一参数.
通知不会吞噬原有异常, 会在 afterThrowingFunction 执行完毕后, 抛出原有异常
vartoAdvise={method: function(throwError){console.log('method exec');if(throwError){thrownewError('method error');}}};varadvisedObject=aop.afterThrowing(toAdvise,'method',function(e){console.log('execption: ',e.message);});// log:// method execadvisedObject.method();// log:// method exec// execption: method erroradvisedObject.method(true);返回一个新的代理对象, 在 matcher 匹配的方法正常返回或抛出异常后, 执行 afterFunction。
通知不会吞噬原有异常, 会在 afterFunction 执行完毕后, 抛出原有异常
vartoAdvise={method: function(throwError){if(throwError){console.log('method exception');thrownewError('error');}console.log('method exec');}};varadvisedObject=aop.after(toAdvise,'method',function(){console.log('after method exec');});// log:// method exec// after method execadvisedObject.method();// log:// method exception// after method execadvisedObject.method(true);返回一个新的代理对象, 在 matcher 匹配的方法执行时, 执行 aroundFunction, aroundFunction 接收一个 ProceedingJoinPoint 对象作为参数, 调用其 proceed/proceedApply 方法将执行原方法.
vartoAdvise={method: function(){console.log('method exec arguments: ',[].slice.call(arguments,0));return'method return value';}};varadvisedObject=aop.around(toAdvise,'method',function(joinPoint){console.log('before method exec');// proceed/proceedApply 可以多次调用, 会多次执行原方法, proceedApply 可以改变 this 和参数信息varresult=joinPoint.proceed();result=joinPoint.proceedApply(null,[1,2]);console.log('method exec result: ',result);console.log('after method exec');});// log:// before method exec// method exec arguments: 1,2,3// method exec arguments: 1,2// method exec result: method return value// after method execadvisedObject.method(1,2,3);创建一个组装了通知行为的对象代理, 会重写符合匹配规则的方法, 织入通知逻辑.
advice 拥有 before, afterReturning, afterThrowing, after, around 中一个或多个方法的对象.
同Function API 下的 ProceedingJoinPoint
matcher 可以为以下三种类型:
- string 匹配拦截对象中属性名与 matcher 相等的方法。
- RegExp 匹配拦截对象中属性名符合 matcher 规则的方法。
- Function 匹配拦截对象中属性名符合 matcher 执行结果的方法, matcher 接收拦截对象和当前属性名称作为参数,返回 true 则表示匹配成功。
vartoAdvise={method: function(){},foo: function(){},foo1: function(){},foo2: function(){},init: function(){}};// 将拦截 toAdvise.methodvaradvisedObject=aop.before(toAdvise,'method',function(){});// 将拦截 toAdvise.foo, toAdvise.foo1, toAdvise.foo2varadvisedObject=aop.before(toAdvise,/^foo/,function(){});varfnMatcher=function(obj,name){returnname!=='init';};// 将拦截 toAdvise.foo, toAdvise.foo1, toAdvise.foo2, toAdvise.methodvaradvisedObject=aop.before(toAdvise,fnMatcher,function(){});提供针对Class方法拦截的 API
创建一个组装了通知行为的类代理, 会重写符合匹配规则的方法, 织入通知逻辑.
advice 拥有 before, afterReturning, afterThrowing, after, around 中一个或多个方法的对象.