2009-06-17 3 views

risposta

30

Ecco cosa ho trovato fino ad ora:

implementazione
  • s' dotvoid, la sintassi pulita, piacevole da usare, l'articolo è una buona introduzione sul perché/come utilizzare il codice dato, supporta introduzioni, ma è sempre sotto controllo,
  • Dojo ha quello che sembra essere un buon incorporato implementazione in dojox, here è una bella introduzione su come usarlo,
  • c'è un plugin per jQuery, jquery-aop, con una sintassi più ruvida, passando oggetti e metodi in un oggetto javascript,
  • AspectJS con una sintassi ancora più ruvida (bisogno di passare tipo di pointcut come argomenti ad un singolo metodo)

Come ho detto, il codice di dotvoid non ha funzionato. ho corretto un po 'e ho trovato qualcosa che sembra funzionare meglio:

InvalidAspect = new Error("Missing a valid aspect. Aspect is not a function."); 
InvalidObject = new Error("Missing valid object or an array of valid objects."); 
InvalidMethod = new Error("Missing valid method to apply aspect on."); 

function doBefore(beforeFunc,func){ 
    return function(){ 
     beforeFunc.apply(this,arguments); 
     return func.apply(this,arguments); 
    }; 
} 

function doAfter(func, afterFunc){ 
    return function(){ 
     var res = func.apply(this,arguments); 
     afterFunc.apply(this,arguments); 
     return res; 
    }; 
} 

Aspects = function(){}; 
Aspects.prototype={ 
    _addIntroduction : function(intro, obj){ 
     for (var m in intro.prototype) { 
       obj.prototype[m] = intro.prototype[m]; 
      } 
     }, 

    addIntroduction : function(aspect, objs){ 
     var oType = typeof(objs); 

     if (typeof(aspect) != 'function') 
     throw(InvalidAspect); 

     if (oType == 'function'){ 
      this._addIntroduction(aspect, objs); 
     } 
     else if (oType == 'object'){ 
      for (var n = 0; n < objs.length; n++){ 
       this._addIntroduction(aspect, objs[n]); 
      } 
     } 
     else{ 
      throw InvalidObject; 
     } 
    }, 

    addBefore : function(aspect, obj, funcs){ 
      var fType = typeof(funcs); 

      if (typeof(aspect) != 'function') 
      throw(InvalidAspect); 

      if (fType != 'object') 
      funcs = Array(funcs); 

      for (var n = 0; n < funcs.length; n++){ 
      var fName = funcs[n]; 
      var old = obj.prototype[fName]; 

      if (!old) 
       throw InvalidMethod; 

      var res = doBefore(aspect,old) 
      obj.prototype[fName] = res; 
     } 
    }, 

    addAfter : function(aspect, obj, funcs) { 
      if (typeof(aspect) != 'function') 
      throw InvalidAspect; 

      if (typeof(funcs) != 'object') 
      funcs = Array(funcs); 

      for (var n = 0; n < funcs.length; n++) 
      { 
      var fName = funcs[n]; 
      var old = obj.prototype[fName]; 

      if (!old) 
       throw InvalidMethod; 

      var res = doAfter(old,aspect); 
      obj.prototype[fName] = res; 
      } 
     }, 

    addAround : function(aspect, obj, funcs){ 
      if (typeof(aspect) != 'function') 
      throw InvalidAspect; 

      if (typeof(funcs) != 'object') 
      funcs = Array(funcs); 

      for (var n = 0; n < funcs.length; n++) 
      { 
      var fName = funcs[n]; 
      var old = obj.prototype[fName]; 
      if (!old) 
       throw InvalidMethod; 

      var res = aspect(old); 
      obj.prototype[fName] = res; 
      } 

      return true; 
     } 
} 
+0

Ha il codice funziona in qualche modo in Internet Explorer? Dato che i miei test non sono andati a buon fine, ho cercato su Google e sembra che IE non abbia un "prototipo" -proprietà ... –

+0

Ho eseguito test su questo su IE7. Funziona bene. Versioni inferiori non testate però. – glmxndr

+1

2014: ho trovato questo framework ancora molto attivo [jsAspect] (https://github.com/antivanov/jsAspect) sembra fare ciò che un AOP dovrebbe fare! –

13

Hai visto meld.js e aop.js da https://github.com/cujojs?

SpringSource offre funzionalità AOP in aggiunta a un sacco di altre cose utili per programmatori Javascript avanzati.

Disclaimer: Lavoro per SpringSource.

+0

È una domanda piuttosto vecchia ... ma grazie per l'aggiunta. – glmxndr

3

Sulla base della soluzione dotvoid, ho creato la mia versione di JS AOP per i miei progetti personali. Fondamentalmente voglio ridurre al minimo i costi di configurazione dell'aspetto, quindi ho aggiunto la funzionalità di configurazione dell'aspetto a Function.prototype.

Function.prototype.applyBefore = function (aspect, targetFuncNames) { 
.... 
} 

ho anche bisogno di supportare callback aync, quali sostenere l'autenticazione e l'autorizzazione per taluni metodi. Per esempio:

var authenticateAspect = function (error, success, context, args) { 
    logger.log('authenticate (applyBefore async) aspect is being called'); 
    var request = $.ajax({ 
     url: "http://localhost/BlogWeb/api/user/authenticate", 
     type: "GET", 
     data: { username:'jeff', pwd:'jeff' }, 
     success: function (data) { 
      if (data) { 
       success(); 
      } else { 
       error(); 
      } 
     }, 
     error: error 
    }); 
    return request; 
}; 

Person.applyBefore(authenticateAspect, 'sendNotification'); 

var p1 = new Person(); 

p1.sendNotification(); 

Per implementare questo, ho bisogno di correre la sicurezza e la e continuare in caso di successo o di interrompere l'esecuzione in caso di fallimento.

var invalidAspect = new Error("Missing a valid aspect. Aspect is not a function."), 
    invalidMethod = new Error("Missing valid method to apply aspect on."); 

///Parameters: aspect - defines the methods we want call before or/and 
///    after each method call ob target obejct 
///   targetFuncNames - target function names to apply aspects 
///Return: it should return a new object with all aspects setup on target object 
Function.prototype.applyBefore = function (aspect, targetFuncNames) { 
    if (typeof (aspect) != 'function') 
     throw invalidAspect; 

    if (typeof (targetFuncNames) != 'object') 
     targetFuncNames = Array(targetFuncNames); 

    var targetObj = this; 
    //error handling function 

    // Copy the properties over onto the new prototype 
    for (var i = 0, len = targetFuncNames.length; i < len; i++) { 
     var funcName = targetFuncNames[i]; 
     var targetFunc = targetObj.prototype[funcName]; 

     if (!targetFunc) 
      throw invalidMethod; 


     targetObj.prototype[funcName] = function() { 
      var self = this, args = arguments; 
      var success = function() { 
       return targetFunc.apply(self, args); 
      }; 
      var error = function() { 
       logger.log('applyBefore aspect failed to pass'); 
       //log the error and throw new error 
       throw new Error('applyBefore aspect failed to pass'); 
      }; 

      var aspectResult = aspect.apply(null, Array.prototype.concat([error, success, self], args)); 
      return aspectResult; 
     }; 
    } 
}; 

piena attuazione può essere trovato alla http://www.jeffjin.net/aop-with-javascript