2012-06-27 25 views
15

Necesito activar la barra de funciones() siempre que la función foo() se dispare. No tengo control sobre la función foo o si cambiará en el futuro. Tengo esta situación regularmente (y lo odio).Añadir código al final de una función existente

escribí esta función para añadir mi código al final de la función foo:

function appendToFunction(fn,code){ 
if(typeof fn == 'function'){ 
    var fnCode = fn.toString() ; 
    fnCode = fnCode.replace(/\}$/,code+"\n}") ; 
    window.eval(fnCode);     // Global scope 
    return true ; 
} 
else{ 
    return false ; 
} 
} 

por ejemplo:

appendToFunction(foo,"bar();"); 

Esto me parece una idea terrible - pero funciona. ¿Puede alguien señalarme en una dirección mejor (más segura) por favor?

EDITAR: foo no es una función específica, sino muchas funciones con las que termino lidiando. No cambian dinámicamente en la página. Pero pueden cambiarse (por ejemplo, solicitudes de validación de formularios) de vez en cuando.

Solución: Me decidí por una versión modificada de Adam's Answer. No es perfecto, pero es mejor que el que tenía:

var oldFoo = foo ; 
foo = function(){ 
     var result = oldFoo.apply(this, arguments); 
     bar(); 
     return result ; 
} 

NB. Tenga cuidado con algunas funciones nativas en IE6/7 que no tienen un método .apply().

+0

posible duplicado de [Adición de código para una función de JavaScript programáticamente] (http://stackoverflow.com/questions/9134686/adding-code-to- a-javascript-function-programtically) –

Respuesta

24

Sólo puede anular foo con una función personalizada que llama a la original.

E.g.

var old_foo = foo; 
foo = function() { 
    old_foo(); 
    bar(); 
} 

También debe pasar ningún argumento foo tiene en él a través de su función de sustitución.

+0

Más simple y un poco más seguro que el mío. Con los cambios para 'arguments' y' return' esto probablemente funcionaría en la mayoría de los casos. – ColBeseder

+0

Esta solución provoca un desbordamiento de pila para mí. Si experimentas lo mismo, la solución de xdazz de abajo funcionó para mí. – Observer

3

Hmm, esto me preocupa, así, usted ha mencionado que

tengo esta situación regular (y lo odio).

¿Le importa si le pregunto en qué situación sigue ocurriendo? ¿Es en una escala corporativa, o en un alcance de proyecto personal? Es evidente que tiene una cabeza plana en sus hombros y sabe que lo que está haciendo es algo fuera de lo común, por lo que me pregunto si existe una solución alternativa.

La razón por la que pregunto es; este enfoque podría abrir una lata de problemas. ¿Qué sucede si foo falla, por ejemplo, o si foo devuelve una evaluación de valor medio? Simplemente anexando bar a la función real no garantiza que se ejecutará. En espera de ello, por otro lado, significa que es más probable que se ejecute, pero aún así, en mi opinión, no es un buen enfoque.

¿Ha considerado revisar la función foo? Sé que esto podría parecer una pregunta tonta, pero valdría la pena si te encuentras con problemas similares en todo momento. Si desea mantener las cosas abstractas, puede adoptar un enfoque de "controlador de eventos", mediante el cual foo desencadena un evento en el window, que a su vez desencadena bar, esto funcionaría en su caso.

Alternativamente, si sabe lo que es foo, y lo que hace, podría enganchar en su prototipo si es un objeto, y luego modificar el código allí apropiadamente. Sin embargo, mencionó que esta función está abierta a cambios, lo que puede hacer que esta opción sea redundante, pero no obstante es una posible solución.

+0

Está en una escala (multi) corporativa, y no tengo control sobre la función 'foo'. A menudo hay otras soluciones alternativas (como setTimeout para verificar los resultados de la función). Pero creo que desencadenar un evento en la ventana parece una ligera mejora en lo que tengo. – ColBeseder

6
function extend(fn,code){ 
    return function(){ 
    fn.apply(fn,arguments) 
    code.apply(fn,argumnets) 
    } 
} 

y utilizar de esta manera:

function appendToFunction(fn,code){ 
    if(typeof fn == 'function'){ 
     var fnCode = fn.toString() ; 
     fnCode = fnCode.replace(/\}$/,code+"\n}") ; 
     window.eval(fnCode);     // Global scope 
     return true ; 
    } 
    else{ 
     return false ; 
    } 
} 

appendToFunction = extend(appendToFunction,function(){/*some code*/}); 

esto le dará el mismo "esto" en ambas funciones

6

Puede hacer algo como esto: THE DEMO.

function foo() { 
console.log('foo'); 
} 

function appendToFunction(fn, callback) { 
    window[fn] = (function(fn){ 
    return function() { 
     fn(); 
     callback(); 
    } 
}(window[fn])); 
} 

appendToFunction('foo', function(){console.log('appended!')}); 

foo(); 
1

Se puede añadir o anteponer un código nuevo a una función existente simplemente fusión ellas utilizando, por ejemplo:

function mergeFunctions(function1, function2, instance1, instance2, numberOfArgumentsToPassToFunc1) { 
    return function() { 
     var _arguments = Array.prototype.slice.apply(arguments); 
     var _arguments1 = _arguments.slice(0, numberOfArgumentsToPassToFunc1); 
     var _arguments2 = _arguments.slice(numberOfArgumentsToPassToFunc1); 
     var that = this; 
     (function(function1, function2) { 
      if (typeof function1 == "function") { 
       if (typeof instance1 != "undefined") { 
        function1.apply(instance1, _arguments1); 
       } 
       else if (that == window) { 
        function1.apply(function1, _arguments1); 
       } 
       else { 
        var compare = mergeFunctions(function(){}, function(){}); 
        if (that.toString() == compare.toString()) { 
         function1.apply(function1, _arguments1); 
        } 
        else { 
         function1.apply(that, _arguments1); 
        } 
       } 
      } 
      if (typeof function2 == "function") { 
       if (typeof instance2 != "undefined") { 
        function2.apply(instance2, _arguments2); 
       } 
       else if (that == window) { 
        function2.apply(function2, _arguments2); 
       } 
       else { 
        var compare = mergeFunctions(function(){}, function(){}); 
        if (that.toString() == compare.toString()) { 
         function2.apply(function2, _arguments2); 
        } 
        else { 
         function2.apply(that, _arguments2); 
        } 
       } 
      } 
     })(function1, function2); 
    } 
} 



Un ejemplo básico sería el siguiente:

// Original function: 
var someFunction = function(){ 
    console.log("original content"); 
}; 

// Prepend new code: 
// -------------------------------------------------------- 
someFunction = mergeFunctions(function() { 
    console.log("--- prepended code"); 
}, someFunction); 

// Testing: 
someFunction(); 

// Outout: 
// [Log] --- prepended code 
// [Log] original content 


// Append new code: 
// -------------------------------------------------------- 
someFunction = mergeFunctions(someFunction, function() { 
    console.log("appended code"); 
}); 

// Testing: 
someFunction(); 

// Output: 
// [Log] --- prepended code 
// [Log] original content 
// [Log] appended code 



Nota que que la función de fusión intenta aplicar el 'esto' esperado a las partes fusionadas, de lo contrario simplemente puede pasarles el 'this' deseado, así como también puede manejar los argumentos relativos.
A ejemplo más general podría ser la siguiente:

function firstPart(a, b) { 
    console.log("--- first part"); 
    console.log("'this' here is:"); 
    console.log(this.name); 
    console.log("a: "+a); 
    console.log("b: "+b); 
} 

function MyObject() { 
    this.x = "x property of MyObject"; 
} 

MyObject.prototype.secondPart = function (y) { 
    console.log(""); 
    console.log("--- second part"); 
    console.log("'this' here is:"); 
    console.log(this.name); 
    this.x = y; 
    console.log("x: "+this.x); 
} 

MyObject.prototype.merged = mergeFunctions(firstPart, MyObject.prototype.secondPart, firstPart, MyObject, 2); 

// Testing 
var test = new MyObject(); 
test.merged("a parameter", "b parameter", "x parameter overrides x property of MyObject"); 

// Console output: 
// [Log] --- first part 
// [Log] 'this' here is: 
// [Log] firstPart 
// [Log] a: a parameter 
// [Log] b: b parameter 
// [Log] 
// [Log] --- second part 
// [Log] 'this' here is: 
// [Log] MyObject 
// [Log] x: x parameter overrides x property of MyObject 
Cuestiones relacionadas