2009-04-25 11 views
12

EDIT: OK, je crois que les solutions suivantes sont valables:crochets fonction Javascript

  1. Utilisez le plugin AOP jQuery. Il enroule l'ancienne fonction avec le crochet dans une fonction sandwich et la réattribue à l'ancien nom de la fonction. Cela provoque l'imbrication des fonctions avec chaque nouveau hook ajouté.
    Si jQuery n'est pas utilisable pour vous, il suffit de piller le code source, il ne semble pas y avoir de dépendances jQuery dans le plugin, et la source est simple et très petite. Avoir un objet décrivant tous les hooks et leurs cibles et un pour stocker la fonction initiale non modifiée. Lors de l'ajout d'un nouveau hook, le wrapping serait refait autour de la fonction d'origine, au lieu de réenvelopper la fonction d'emballage précédente.
    Vous pouvez échapper des fonctions imbriquées et obtenir deux objets à gérer à la place. Potentiellement, cela pourrait également signifier une manipulation plus facile du crochet, si vous ajoutez/retirez des crochets souvent et hors service.

Je vais aller avec le premier, puisque c'est déjà fait, et je n'ai pas de problème à se soucier. Et puisque les fonctions d'origine ne sont pas affectées, même si je change de méthodes d'accrochage, je n'aurai besoin de refaire l'ajout de crochet, qui pourrait être juste une simple recherche & remplacer les opérations.


Salut,

Est-il possible de créer un mécanisme, dans lequel fonctionner A pourrait avoir un ensemble de crochets (fonctions qui exécuteront avant/après la fonction A)?

Idéalement, la fonction A ne serait pas au courant de la fonctionnalité d'accrochage, de sorte que je n'ai pas besoin de modifier le code source de la fonction A pour appeler les crochets. Quelque chose comme:

A = function(){ 
    alert("I'm a naive function"); 
}; 
B = function(){ 
    alert("I'm having a piggyback ride on function A!"+ 
      "And the fool doesn't even know it!"); 
}; 
addHook(B, A)//add hook B to function A 
A() 
//getting alerts "I'm a naive function"/"I'm having a 
//piggyback ride on function A! And the fool doesn't even know it!" 

J'ai essayé de pirater quelque chose pendant quelques heures, mais jusqu'à présent, pas de chance.

+0

c'est une bonne question, altho je doute qu'il y aura une réponse positive. Vous pouvez certainement le faire mais avec une sorte de solution de contournement. Je bookmarking ceci. –

Répondre

10

Jetez un oeil à jQuery's AOP plugin. En général, google "programmation orientée aspect javascript".

+4

jQuery! = Javascript. Cela est important, par exemple, si vous programmez sur la plate-forme Facebook, et probablement aussi dans d'autres environnements "sandboxés". –

+0

@George: les techniques démontrées s'appliquent toujours. Jusqu'à présent, Greg est le seul à publier du code utilisable * ici *. – Shog9

+0

Merci pour le lien et la mention d'AOP, je n'étais pas familier avec lui. Je suis capable et j'utilise jQuery, donc ça pourrait marcher. Essayer de comprendre le plugin en ce moment. – Seyen

12

peut-être pas assez, mais il semble fonctionner ...

<script> 

function A(x) { alert(x); return x; } 
function B() { alert(123); } 

function addHook(functionB, functionA, parent) 
{ 
    if (typeof parent == 'undefined') 
     parent = window; 

    for (var i in parent) 
    { 
     if (parent[i] === functionA) 
     { 
      parent[i] = function() 
      { 
       functionB(); 
       return functionA.apply(this, arguments) 
      } 

      break; 
     } 
    } 
} 

addHook(B, A); 

A(2); 

</script> 
+1

Merci! J'ai pensé à celui-ci, et cela fonctionne, mais vous obtenez l'imbrication avec cette méthode, puisque chaque nouveau crochet enveloppe tous les crochets précédents: hookC (hookB (hookA (functionA.apply (this, arguments)))) I ' Je ne sais pas si cela affecte les performances de quelque façon que ce soit, mais cela ne me semble pas correct/sûr. Est-ce que 'parent' est utilisé pour que' apply (this, arguments) 'soit lié correctement? – Seyen

2

Cette réponse est non définitive, mais plutôt démonstratif d'une technique différente que celles proposées jusqu'ici. Ceci tire parti du fait qu'une fonction dans Javascript est un objet de première classe, et en tant que tel, a) vous pouvez le passer comme valeur à une autre fonction et b) vous pouvez lui ajouter des propriétés. Combinez ces caractéristiques avec les méthodes "call" (ou "apply") intégrées de la fonction, et vous avez vous-même un point de départ vers une solution.

var function_itself = function() { 
    alert('in function itself'); 
} 
function_itself.PRE_PROCESS = function() { 
    alert('in pre_process'); 
} 
function_itself.POST_PROCESS = function() { 
    alert('in post_process'); 
} 

var function_processor = function(func) { 
    if (func.PRE_PROCESS) { 
     func.PRE_PROCESS.call(); 
    } 
    func.call(); 
    if (func.POST_PROCESS) { 
     func.POST_PROCESS.call(); 
    }   
} 
+0

Cela fonctionne, mais vous devez utiliser function_processor pour appeler function_itself dans tous les endroits où il serait appelé, ce qui va à l'encontre du but. Le code peut rapidement être transféré dans une forêt d'appels de fonctions_processeur. – Seyen

3

réponse très simple:

function someFunction() { alert("Bar!") } 
var placeholder=someFunction; 
someFunction=function() { 
    alert("Foo?"); 
    placeholder(); 
} 
1

La fonction suivante vous donnera avant et après des crochets qui peuvent être empilés. Donc, si vous avez un certain nombre de fonctions potentielles qui doivent s'exécuter avant la fonction donnée ou après la fonction donnée, alors cela serait une solution de travail. Cette solution ne nécessite pas jQuery et utilise des méthodes de tableau natives (pas de shims requis). Il devrait également être sensible au contexte, donc si vous appelez la fonction d'origine avec un contexte, vous devriez exécuter chaque fonction avant et après.

// usage: 
/* 
function test(x) { 
    alert(x); 
} 

var htest = hookable(test); 

htest.addHook("before", function (x) { 
    alert("Before " + x); 
}) 
htest.addHook("after", function (x) { 
    alert("After " + x); 
}) 

htest("test") // => Before test ... test ... After test 
*/ 
function hookable(fn) { 
    var ifn = fn, 
     hooks = { 
      before : [], 
      after : [] 
     }; 

    function hookableFunction() { 
     var args = [].slice.call(arguments, 0), 
      i = 0, 
      fn; 
     for (i = 0; !!hooks.before[i]; i += 1) { 
      fn = hooks.before[i]; 
      fn.apply(this, args); 
     } 
     ifn.apply(this, arguments); 
     for (i = 0; !!hooks.after[i]; i++) { 
      fn = hooks.after[i]; 
      fn.apply(this, args); 
     } 
    } 

    hookableFunction.addHook = function (type, fn) { 
     if (hooks[type] instanceof Array) { 
      hooks[type].push(fn); 
     } else { 
      throw (function() { 
       var e = new Error("Invalid hook type"); 
       e.expected = Object.keys(hooks); 
       e.got = type; 
       return e; 
      }()); 
     } 
    }; 

    return hookableFunction; 
} 
0

Voici ce que je l'ai fait, pourrait être utile dans d'autres applications comme celle-ci:

//Setup a hooking object 
a={ 
    hook:function(name,f){ 
     aion.hooks[name]=f; 
    } 
}a.hooks={ 
    //default hooks (also sets the object) 
}; 

//Add a hook 
a.hook('test',function(){ 
    alert('test'); 
}); 

//Apply each Hook (can be done with for) 
$.each(a.hooks,function(index,f){ 
    f(); 
}); 
0

Je ne sais pas si cela sera utile. Vous avez besoin de modifier la fonction d'origine, mais une seule fois et vous n'avez pas besoin de garder l'éditer pour les crochets de tir