AOP参考资料:
aop在spring中大量被使用到,说白了就是往目标代码中织入关注的切面代码,在spring中需要使用proxy或cglib中实现。
鉴于JavaScript的灵活性,在js中实现aop比想象中灵活得多。
下面写了个简单的实现,需要比较粗糙,pointcut什么的没有体验,但总体思想和aop一致。
1、
/* 绑定的AOP */ bind:function(obj,advice){ //如果已经绑定过了,就不再重复绑定了 if(oldObjectFn[obj]!=null){ return; } //生成织入器 var inject=injectCreator(advice); dealObjectFunction(obj,inject); }
aop绑定的入口在这里,这里根据传入的advice生成一个织入器。
2、
function dealObjectFunction(obj,inject){ oldObjectFn[obj]={}; for(var name in obj){ if(obj.hasOwnProperty(name)){//原型链下的属性不操作 var val=obj[name]; if(isFunction(val)){//只操作function var oldfn=val; var newfn=inject(name,val,obj);//把切面代码织入到旧代码中 obj[name]=newfn; oldObjectFn[obj][name]=oldfn;//旧方法保存起来 } } } }
筛选出目标函数,当然这里写的比较粗糙,只是简单把所有的方法的取出来(没得选)
var newfn=inject(name,val,obj)
通过这个方法,编织出一个新的函数,保存旧函数,并替换目标函数。
3、 织入代码的具体实现
var injectCreator=function(advice){ return function(name,oldfn,obj){ var before=advice.before||function(){}, after=advice.after||function(){}, afterReturn=advice.afterReturn||function(){}, afterThrowing=advice.afterThrowing||function(){}, around=advice.around||function(fn){ var ret=fn(); return ret; }, fn=function(){ var args=Array.prototype.slice.call(arguments); before.apply(obj,[name].concat(args)); //前置通知带上方法明 var ret=around.call(obj,function(){ try{ return oldfn.apply(obj,args); //执行原有方法,并返回原方法的执行结果 }catch(e){ afterThrowing.call(obj,e); throw e; } }); afterReturn.call(obj,ret); after.call(obj); return ret; }; return fn; } }
对advice进行简单修饰后,按先后顺序用before、around、afterReturn、after对旧方法进行装饰,放回新方法。
var args=Array.prototype.slice.call(arguments);
因为arguments不是数组,为了让他居然数组的特性,进行上面的处理。
4、解绑
unbind:function(obj){ var map=oldObjectFn[obj]; if(map!=null){ //把旧的方法放回去 for(var key in map){ var fn=map[key]; obj[key]=fn; } oldObjectFn[obj]=null; } }