当前位置: 代码迷 >> JavaScript >> js兑现的AOP雏形
  详细解决方案

js兑现的AOP雏形

热度:133   发布时间:2012-11-19 10:18:51.0
js实现的AOP雏形
  老早以前的东西了,发出来分享下。目前支持aop的框架实在很少,功能也挺残废的~ 运行还算稳定,不会对this指针造成干扰,经测试可对对象的方法、独立函数、构造函数等各种添加AOP支持,也可以解除AOP支持。使用advice链式结构实现,最大的特点应该是支持参数/返回值控制(即每个advice均有一个入口/出口,可以自由定制输入/输出策略)。不多说了,上代码,直接拿来用应该是木有问题的但是目前还只实现了before和after两个joinpoint,后续可能扩展一些,参数/返回值策略也有些小单调虽然扩展性不咋地但是基本需求应该能满足。后续如果有时间的话可能从这两点完善一下。

//外部接口

var AopUtil = {};

(function() {

    AopUtil.ALLOW_IN = 1;

    AopUtil.ALLOW_OUT = 2;

    var original = {};

    //缓存数据,新增before advice的时候会用到

    var beforeAdviceCounter = 0;

    //将原始方法变成代理方法的方法

    var createProxyMethod = function(originalItem) {

        return function() {

            var currentArg = arguments;

            var currentReturn = arguments;

            var lastReturn = arguments;

            //计算组合策略(参数+返回值策略)中的参数策略

            //isInAllowed为策略值二进制表示中的最低位值,isOutAllowed为次低位

            var isInAllowed, isOutAllowed;

            //当前函数的返回值

            var result;

            for (var i in originalItem.adviceChain) {

                //读取策略组

                isInAllowed = originalItem.adviceChain[i].strategy;

                isOutAllowed = isInAllowed >> 1;

                isInAllowed = isInAllowed - (isInAllowed >> 1 << 1);

                isOutAllowed = isOutAllowed - (isOutAllowed >> 1 << 1);

                if (isInAllowed) currentArg = lastReturn;

                else currentArg = arguments;

                currentReturn = [originalItem.adviceChain[i].method.apply(this, currentArg)];

                if (isOutAllowed) lastReturn = currentReturn;

            }

            return lastReturn[0];

        }

    }

    //对原始方法添加AOP支持

    var attachToAop = function(methodName, strategy) {

        if (original[methodName])  return null;

        var sourceMethod = eval(methodName);

        if (!sourceMethod) return null;

        //初始化adviceChain

        original[methodName] = {};

        original[methodName].backup = sourceMethod;

        original[methodName].adviceChain = [{method : sourceMethod, strategy : strategy}];

        eval(methodName  + " = createProxyMethod(original[methodName])");

    }

    //外部接口之添加before joinpoint

    AopUtil.before = function(methodName, command, strategy) {

        if (!original[methodName]) attachToAop(methodName, 3);

        original[methodName].adviceChain.splice(

            beforeAdviceCounter, 0, {

                method : command,

                strategy : (strategy ? strategy : AopUtil.SKIP_ARG)

            }

        );

        ++beforeAdviceCounter;

    }

    //外部接口之添加after joinpoint

    AopUtil.after = function(methodName, command, strategy) {

        //原始函数两端全开

        if (!original[methodName]) attachToAop(methodName, 3);

        original[methodName].adviceChain.push({

            method : command,

            strategy : (strategy ? strategy : AopUtil.SKIP_ARG)

        });

    }

    //清空目标方法上的所有advice

    AopUtil.clearAdvice = function(methodName) {

        if (original[methodName]) {

            eval(methodName + "= original[methodName].backup");

            original[methodName] = null;

        }

    }
})();



靠,在这个编辑器里头调格式真够累的...下面是使用实例



//先定义一个类

var Class = function() {

    //私有成员变量

    var value = "value";

    this.alert = function() {

        alert(value);

    }

    this.setValue = function(newValue) {

        value = newValue;

    }

}

AopUtil.before("Class", function() {

    alert("你正在初始化一个实例!");

});

//初始化一个实例,这个时候会输出"你正在初始化一个实例!"这句话;

//实际上,当直接执行"Class()"的时候也会输出这句话。如果仅希望在Class被当做构造函数使用时输出,

//可以通过this指针来判断,就像这样:

//AopUtil.before("Class", function() {

//    if (!typeof(this).toLowerCase() == "object") alert("你没有把Class当做构造函数!");

//    else alert("你正在初始化一个实例!");

//});

var a = new Class();

//比较高级的应用:

AopUtil.before("a.alert", function() {

    alert(0);

}, AopUtil.ALLOW_IN + AopUtil.ALLOW_OUT);

AopUtil.before("a.alert", function() {

    alert(1);

}, AopUtil.ALLOW_IN + AopUtil.ALLOW_OUT);

AopUtil.before("a.alert", function() {

    alert(2);

}, AopUtil.ALLOW_IN + AopUtil.ALLOW_OUT);

AopUtil.after("a.alert", function() {

    alert(3);

}, AopUtil.ALLOW_IN + AopUtil.ALLOW_OUT);

AopUtil.after("a.alert", function() {

    alert(4);

}, AopUtil.ALLOW_IN + AopUtil.ALLOW_OUT);

AopUtil.after("a.alert", function() {

    alert(5);

}, AopUtil.ALLOW_IN + AopUtil.ALLOW_OUT);

//有兴趣的同僚们觉得执行"a.alert()"的时候应该输出啥?
  相关解决方案