`

javascript 实现AOP

 
阅读更多

你相信么,在JavaScript只需一个函数5行代码即可实现完整的面向方面AOP编程功能。这5行代码的功能包括:

1、无限层次的函数无害拦截

2、函数执行前拦截
3、检查函数的参数值
4、重新设定函数的参数值
5、函数执行后拦截
6、检查函数执行后的返回结果
7、重新设定函数的返回结果

虽然动态函数式语言的效率是一个存在的问题,但是对于它的高度灵活性,简直让人令人惊叹不已,剧赞。
这个小小的函数源自于和爱明兄的一次讨论:在javascript中不修改源代码的形式扩充新功能的完美方式。
至于为啥要不直接修改别人源代码库,你想,当你辛苦修改后,人家发布了一个新版本,你是不是又要重新
修改一次?如果修改的地方少还好,多了的话,嘿嘿!所以,不是你的东西,最好不要动,除非你确定要自
己完全维护所有的代码(如果你实在太闲)。

为了给开发人员一个榜样,俺不得不写一个patch样例,最开始俺写的patch方式是这样滴:
FCKEditingArea.prototype.FckMediaStart = FCKEditingArea.prototype.Start;
FCKEditingArea.prototype.Start =  function( html, secondCall )
{
  var sHeadExtra = '<link href="' + FCKConfig.PluginsPath + 'media/css/fck_media.css" rel="stylesheet" type="text/css" _fcktemp="true" />' ;
  html = html.replace( FCKRegexLib.HeadCloser, sHeadExtra + '$&' ) ;
  return this.FckMediaStart(html, secondCall);
}

俺觉得这种补丁方式是不太让我满意的

爱民兄提到他喜欢这样patch方式:
FCKEditingArea.prototype.Start = function( func ) {
  return function( html ) {
    html = html.replace( FCKRegexLib.HeadCloser, sHeadExtra + '$&' ) ;
    return func.apply(this, arguments);
  }
}(FCKEditingArea.prototype.Start);

这种方式的确不存在漏洞了,perfect,但是却把我彻底弄懵了,看得我头大啊!琢磨了好久才算明白过来。
不过从管理角度考虑,如果程序中到处都是这样的方式,那么将大大降低程序的可读性,增加维护代码的成本
(ps,要开发维护这样的代码,你不得不请JS高级程序员才行)。
为了限制匿名函数的滥用导致的可读性下降,俺写了一个Inject()函数的雏形(将匿名函数的使用限制在其中),
经过爱民兄修改,然后又是讨论,然后我们又修改,如此反复,达到这个最终版本(也许还不是,谁知道呢)。


好了,荣誉归于爱民,臭鸡蛋归于俺,闲话少说,看看代码吧,不算上注释,这个Inject函数正好5行。如果你清楚
的知道匿名函数的特点,那么这个函数,你就不难看懂,否则你就只能管用了。用法在注释的例子里,够简单吧。

function Inject( aOrgFunc, aBeforeExec, aAtferExec ) {
  return function() {
    if (typeof(aBeforeExec) == 'function') arguments = aBeforeExec.apply(this, arguments) || arguments;
    //convert arguments object to array
    var Result, args = [].slice.call(arguments);
    args.push(aOrgFunc.apply(this, args));
    if (typeof(aAtferExec) == 'function') Result = aAtferExec.apply(this, args);
    return (typeof(Result) != 'undefined')?Result:args.pop();
  }
}

使用新的Inject方式的代码如下:
FCKMediaProcessor.EditingArea_StartBefore = function ( html, secondCall )
{
  var sHeadExtra = '<link href="' + FCKConfig.PluginsPath + 'media/css/fck_media.css" rel="stylesheet" type="text/css" _fcktemp="true" />' ;
  html = html.replace( FCKRegexLib.HeadCloser, sHeadExtra + '$&' ) ;
  //在执行前修改了参数值,所以返回修改后的参数
  return arguments;
}
FCKEditingArea.prototype.Start =  Inject(FCKEditingArea.prototype.Start, FCKMediaProcessor.EditingArea_StartBefore);


ok,下面将继续增强 Inject的功能,将会把浪子提到的控制原函数是否执行加上。
本增强版本和上面的Inject函数的版本使用上略有差别,使用规范如下:

执行前调用(BeforeExec)
如果修改了参数值,必须这样返回修改的参数: return new Arguments(arguments);
如果没有返回值或者返回undefined那么正常执行,返回其它值表明不执行原函数,该值作为替代的原函数返回值。
执行后调用(AfterExec)
如果希望取得函数的返回值,必须在原参数表后面增加一个参数: result
如果希望知道原函数是否被执行,那么必须在 result参数的后面再增加一个参数: isDenied 该值为真表明没有执行原函数
如果希望修改函数的返回值,那么你只要简单的把修改后的值返回即可。

示例:假设我们要拦截一个 doTest 函数,修改它的参数值a,在原参数值上+1,并在它的函数返回值上也+1:
//定义测试函数 doTest
var doTest = function (a) {
  alert('dotest 运行中');
  return a;
};

function beforeTest(a) {
  alert('执行前参数: a='+a);
  a += 1;
  return new Arguments(arguments);
}

function afterTest(a, result, isDenied) {
//这里不会体现出参数a的改变,如果原函数改变了参数a。因为在js中所有参数都是值参。
  alert('执行后参数: a='+a+'; result='+result+';isDenied='+isDenied);
  return result+1;
}
 
//注入该doTest函数
doTest = Inject(doTest, beforeTest, afterTest);

//执行 doTest并显示结果
alert (doTest(2));

和爱民兄谈论后,修订后的新的Inject函数如下,这下功能全了,具体代码也不过十多行:


function Arguments(args) {
  //convert arguments object to array
  this.value = [].slice.call(args);
}
function Inject( aOrgFunc, aBeforeExec, aAtferExec ) {
  return function() {
    var Result, isDenied=false, args=[].slice.call(arguments);
    if (typeof(aBeforeExec) == 'function') {
      Result = aBeforeExec.apply(this, args);
      if (Result instanceof Arguments) //(Result.constructor === Arguments)
        args = Result.value;
      else if (isDenied = Result !== undefined)
        args.push(Result)
    }

    !isDenied && args.push(aOrgFunc.apply(this, args)); //if (!isDenied) args.push(aOrgFunc.apply(this, args));

    if (typeof(aAtferExec) == 'function')
      Result = aAtferExec.apply(this, args.concat(isDenied));
    else
      Result = undefined;

    return (Result !== undefined ? Result : args.pop());
  }
}

注:本文转自http://blog.sina.com.cn/s/blog_67b072ce0100ipza.html

分享到:
评论

相关推荐

    JavaScript实现AOP详解(面向切面编程,装饰者模式)

    JavaScript实现AOP的思路? 通常,在 JavaScript 中实现 AOP,都是指把一个函数“动态织入”到另外一个函数之中,具体的实现技术有很多,下面我用扩展 Function.prototype 来做到这一点。请看下面代码:

    AOP基本功能在JavaScript中的研究和实现.pdf

    * 闭包技术:一种特殊的函数,可以访问外部函数的变量,用于实现AOP。 * JavaScript AOP基本功能:使用闭包技术实现的AOP基本功能,可以将业务逻辑和非业务逻辑分离,从而提高软件的可维护性和可重用性。

    JavaScript中AOP的实现与应用

    在JavaScript中实现AOP,可以通过不同的方式来完成。文中提到了三种通知类型,分别是前置通知(before)、后置通知(after)、环绕通知(around)。它们的作用如下: 1. 前置通知(before):在方法执行之前执行的...

    AOP面向切面编程的JavaScript实现

    在JavaScript中实现AOP还可以借助第三方库,如`aspectjs`或`aop-js`。这些库提供了一套API,用于定义切面、通知(advises,如前置通知、后置通知、环绕通知等)和连接点(join points)。这些库可以帮助开发者更...

    javascript _aop

    在 JavaScript 中实现 AOP,通常采用两种主要方法:代理模式(Proxy)和装饰器(Decorator)。代理模式通过在目标对象前创建一个代理,控制对目标对象的访问,可以在调用目标方法前后插入额外的行为。装饰器模式则是...

    JavaScript之AOP编程实例

    通过以上内容,我们可以了解到在JavaScript中实现AOP编程的原理和技术细节。这不仅包括AOP的基本概念、实现方式,还包括了如何将AOP应用到实际项目中的示例和潜在的注意事项。这些知识点对于理解面向切面编程,以及...

    JavaScript实现的相册

    本项目是一个使用JavaScript实现的相册,旨在提供一种动态、直观的方式来展示和浏览图片。以下将详细介绍这个JavaScript相册的实现原理和相关知识点。 1. **DOM操作**:JavaScript通过Document Object Model(DOM)...

    JavaScript AOP编程实例

    JavaScript AOP(面向切面编程)是一种...以上介绍的知识点不仅涵盖了AOP编程的基本概念,还涉及了具体的JavaScript实现技术。对于希望深入学习和应用JavaScript AOP编程的开发者来说,理解和掌握这些知识点非常重要。

    AOP编程技术分享

    AOP编程技术分享,包括iOS和javascript等多个平台实现

    基于js的简易aop框架

    “源码”标签表明这个项目包含了实现AOP框架的原始代码,对于学习和理解JavaScript AOP工作原理非常有价值。而“工具”标签可能意味着这个框架可以作为开发工具,帮助开发者更方便地在JavaScript应用中应用AOP概念。...

    使用AOP改善javascript代码

    在JavaScript中,AOP同样能够提供代码重构、增强模块间解耦、代码复用等优点。下面将根据文档提供的内容,详细解释在JavaScript中如何使用AOP来改善代码。 1. 防止window.onload被二次覆盖 在JavaScript中,window....

    javascript的基础语法,面向对象的实现和设计模式实现

    5.AOP Jquery [jQuery][9] [jQuery架构设计与实现][10] [jQuery选择器库][11] [zepto][12] 1.jQuery 插件推荐 2. jQuery 中 closure Javascript-Design-Pattern 1. Singleton-Pattern 2. Chaining 3.Factory-...

    javascript AOP 实现ajax回调函数使用比较方便

    给出的代码实现了一个简单的AOP装饰器模式,用于在方法执行前后插入额外的行为。装饰器模式是一种设计模式,它可以动态地给一个对象添加一些额外的职责,使得我们可以将关注点分离,保持代码的整洁和可扩展性。 ...

    Javascript aop(面向切面编程)之around(环绕)分析

    JavaScript 中的 AOP 实现虽不如 Java 或 .NET 那样成熟,但依然可以通过一些技巧实现类似功能。 在 AOP 中,"通知" 是执行切面逻辑的关键部分。有四种主要的通知类型: 1. 前置通知(Before Advice):在目标方法...

    商城系统源码,技术(Spring MVC AOP)+MyBatis+Ajax+JavaScript

    本文将详细解析标题和描述中提到的“商城系统源码”,以及其技术栈Spring MVC、AOP、MyBatis、Ajax和JavaScript,并结合文件名称"shop",探讨这些技术在构建一个商城系统中的应用。 首先,商城系统是电子商务平台的...

Global site tag (gtag.js) - Google Analytics