前端工程化借鉴了很多后端的成功经验,设计模式,MVC,组件化与模块化等,再结合前端本身的分层与分治的特点,逐渐变得复杂。
在angular里ioc,di的概念也开始盛行,而且结合的还不错,不过aop这种说法还真少见,可能是我太孤陋寡闻了吧,不免去百度一下。
一开始听到前端AOP这个提法我还有些吃惊,我是会后端开发的,SPRING的AOP已深入人心,面向切片与切入点都是核心概念,但是javascript做AOP还是真没在项目里做过。js是解释型的语言,语法松散灵活,是一种非强类型的语言,它是一种天生的函数式语言,除了值类型,一些皆为对象,包括函数,前端开发一直以来都是一个页面一个页面地生产的,做AOP的意义何在?而且也没有听说哪个框架里有AOP。后来一查,还真有,在DOJO这个框架里比较流行,不过DOJO我一直没用过,所以就没深入去了解。
所以,我说AOP如果需要用的话,可以用JS闭包来做,在调用其他方法前先调用一个切面方法。现在想想,我觉得这样说也没错,前端模块化基本都是用闭包来实现的,如果不做封装,都是松散的JS文件,何谈AOP?
AOP一般用在哪儿呢?日志记录、权限检查、事务处理,我想权限检查和事务处理最好是放到后端去做,一是为了安全,二是好控制,事务很难在界面逻辑上控制,但在后端的业务逻辑或数据库层就容易的多,而权限检查在前端做就不安全,因为JS和HTML都是文本格式的,代码在前端是暴露的,只能做一些弱检查。日志记录可能是前端AOP主要的一个应用方向吧,但前端代码是在浏览器里运行的,日志记录也很难记到文件里,只能利用cookie或console,前者不适应记录日志,因为会降低性能,而后者主要用来做调试代码用,这么看来,我觉得AOP的作用并不明显,了解一下即可。
使用回调的方式实现AOP:
advice = function(originalFunc){
console.log("before function");
originalFunc();
console.log("after function");
}
varobj ={
foo: function(){
console.log('foo');
}
}
advice(obj.foo)
这最简单不过了,要想使用AOP,我们不得不通过advice来调用每一个方法,这种方式的确不够友好。
需要做一些封装,使用闭包来控制:(以下代码来源于网络)
function around(obj, prop, advice){
var exist =obj[prop];
var previous = function(){
return exist.apply(obj, arguments);
};
var advised =advice(previous);
obj[prop] = function(){
//当调用remove后,advised为空
//利用闭包的作用域链中可以访问到advised跟previous变量,根据advised是否为空可以来决定调用谁
return advised ?advised.apply(obj, arguments) : previous.apply(obj, arguments);
};
return{
remove: function(){
//利用闭包的作用域链,在remove时将advised置空,这样执行过程中不会进入本次around
//这几个不能删
//obj[prop] = exist;
advised = null;
advice = null;
//previous = null;
//exist = null;
//obj = null;
}
}
}
var count = 1;
advice = function(originalFunc){
var current = count++;
return function() {
console.log("before function " +current);
originalFunc.apply(this, arguments);
console.log("after function " +current);
}
}
var obj ={
foo: function(arg){
console.log(this.name + " and " +arg);
},
name: "obj"
}
h1 = around(obj, 'foo', advice);
h2 = around(obj, 'foo', advice);
obj.foo('hello world');
//before function 2
//before function 1
//obj and hello world
//after function 1
//after function 2
h1.remove();
obj.foo('hello world');
//before function 2
//obj and hello world
//after function 2
h2.remove();
obj.foo('hello world');
//obj and hello world
around前面两个参数指定了对象和对象上的方法,后一个参数指定了切面方法,调用apply的目的是防止this指向脱离obj。
为了记录个日志调试一下,这么大费周章,而且代码即不易于理解也显多余,看来前端AOP的用处真的不太大呀。