2009-04-25 11 views
12

EDIT: Bueno, yo creo que las soluciones siguientes son válidos:Javascript enlaces de funciones

  1. utilizar el plugin jQuery AOP. Básicamente, envuelve la función anterior junto con el gancho en un sándwich de función y lo reasigna al nombre de la función anterior. Esto causa la anidación de funciones con cada nuevo gancho adicional.
    Si jQuery no se puede utilizar para usted, simplemente saquee el código fuente, no parece haber ninguna dependencia de jQuery en el complemento, y la fuente es simple y muy pequeña.

  2. Tienen un objeto que describe todos los ganchos y sus destinos y uno para almacenar la función inicial no modificada. Al agregar un nuevo gancho, el envoltorio se volvería a hacer alrededor de la función original, en lugar de volver a envolver la función de envoltura anterior.
    Usted escapa de las funciones anidadas, y obtiene dos objetos para manejar en su lugar. Potencialmente, esto también podría significar un manejo de gancho más fácil, si agrega/elimina ganchos a menudo y fuera de servicio.

Voy a ir con el primero, ya que ya está hecho, y no tengo el rendimiento que preocuparse. Y dado que las funciones originales no se ven afectadas, incluso si cambio los métodos de enganche, solo tendré que volver a hacer la adición del gancho, que podría ser simplemente una búsqueda simple & reemplazar operaciones.


Hola,

¿Es posible crear un mecanismo, en el que funcionará A podría tener una serie de ganchos (funciones que se ejecutarán antes/después de la función A)?

Lo ideal es que la función A no tenga en cuenta la funcionalidad de enganche, por lo que no es necesario modificar el código fuente de la función A para llamar a los enganches. Algo como:

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!" 

He intentado hackear algo durante un par de horas, pero hasta ahora no tuve suerte.

+0

esta es una buena pregunta, Altho i duda habrá una respuesta positiva. Sin duda puede hacerlo, pero con algún tipo de solución. Estoy marcando esto. –

Respuesta

10

Eche un vistazo a jQuery's AOP plugin. En general, google "programación orientada a aspectos de JavaScript".

+4

jQuery! = Javascript. Esto importa, por ejemplo, si está programando en la plataforma de Facebook, y probablemente también en otros entornos de "espacio aislado". –

+0

@George: las técnicas demostradas aún se aplican. Hasta el momento, Greg es el único que ha publicado el código utilizable * aquí *. – Shog9

+0

Gracias por el enlace y la mención de AOP, no estaba familiarizado con él. Puedo y uso jQuery, así que esto podría funcionar. Tratando de descubrir el plugin en este momento. – Seyen

12

Puede que no sea bonita, pero parece que funciona ...

<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

¡Gracias! Pensé en esto, y funciona, pero obtienes anidamiento con este método, ya que cada nuevo gancho envuelve todos los ganchos anteriores: hookC (hookB (hookA (functionA.apply (this, arguments)))) I ' No estoy seguro si esto afecta el rendimiento de alguna manera, pero no se siente bien/seguro. ¿Se utiliza 'parent' para que esto de' apply (this, arguments) 'se vincule correctamente? – Seyen

2

Esta respuesta no es definitiva, sino más bien demostrativa de una técnica diferente que las ofrecidas hasta el momento. Esto aprovecha el hecho de que una función en Javascript es un objeto de primera clase, y como tal, a) puede pasarlo como un valor a otra función yb) puede agregarle propiedades. Combine estos rasgos con los métodos incorporados de "llamada" (o "aplicar") de la función, y usted mismo comienza a buscar una solución.

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

Esto funciona, pero luego debe usar function_processor para llamar a function_itself en todos los lugares donde se llamaría, lo que de alguna manera frustra el propósito. El código puede convertirse rápidamente en un bosque de llamadas a function_processor. – Seyen

3

respuesta muy simple:

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

La siguiente función le dará antes y después de ganchos que se pueden apilar. Entonces, si tiene varias funciones potenciales que deben ejecutarse antes de la función dada o después de la función dada, entonces esta sería una solución de trabajo. Esta solución no requiere jQuery y utiliza métodos de matriz nativa (no se requieren calzas). También debe ser sensible al contexto, por lo que si llama a la función original con un contexto, debe ejecutar cada función anterior y posterior de la misma manera.

// 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

Aquí es lo que hice, podría ser útil en otras aplicaciones como esta:

//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

No sé si esto será útil. Sí es necesario modificar la función original, pero sólo una vez y no es necesario para mantener a editarlo para los ganchos de tiro

Cuestiones relacionadas