Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append code to the end of an existing function

I need to trigger function bar() whenever function foo() fires. I have no control over function foo or whether it will change in the future. I have this situation regularly (and I hate it).

I wrote this function to add my code to the end of function 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 ;
}
}

eg:

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

This strikes me as a terrible idea - but it works. Can somebody point me in a better (safer) direction please.

EDIT: foo is not a specific function, but many functions that I wind up dealing with. They don't change dynamically in the page. But they may be changed (eg. form validation demands) from time to time.

Solution: I settled on a modified version of Adam's Answer. It's not perfect, but it's better than what I had:

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

NB. Watch out for some native functions in IE6/7 that don't have an .apply() method.

like image 534
ColBeseder Avatar asked Jun 27 '12 08:06

ColBeseder


People also ask

How do you append the results of a function in Python?

append method in Python is to insert an item at the end of the list, but it doesn't return anything but None . In your code: y = x. append(9) : you running x. append(9) and put the result into y .


4 Answers

You can just override foo with a custom function that calls the original.

E.g.

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

You should also pass any arguments foo takes into it via your replacement function.

like image 126
Adam Heath Avatar answered Oct 04 '22 11:10

Adam Heath


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

and use it like this:

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*/});

this will give you the same "this" in both functions

like image 23
cuzzea Avatar answered Oct 04 '22 11:10

cuzzea


You could do something like this: 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();
like image 6
xdazz Avatar answered Oct 04 '22 11:10

xdazz


Hmm, this concerns me as well, you mentioned that

I have this situation regularly (and I hate it).

Do you mind if I ask in what scenario this keeps occurring? Is it in a corporate scale, or on a personal project scope? You've clearly got a level head on your shoulders and know that what you're doing is out of the ordinary, so I'm wondering if there is an alternatively solution.

The reason I ask is; this approach could potentially open a can of problems. What if foo fails for example, or if foo returns a value mid evaluation? By simply appending bar to the actual function doesn't guarantee it will execute. Pre-pending it on the other hand means it's more likely to be executed, but still in my opinion isn't a good approach.

Have you considered revising the function foo? I know this might seem like a silly question, but it might be worth it if you're encountering similar problems throughout. If you want to keep things abstracted you could adopt an "event handler" approach, whereby foo triggers an event on the window, which in turn then triggers bar, would this work in your case.

Alternatively, if you know what foo is, and what it does, you could hook into it's prototype if it's an object, and then amend the code there appropriately. You did however mention that this function is open to change, which may make this option redundant, but it's a possible solution nonetheless.

like image 3
Richard Avatar answered Oct 04 '22 09:10

Richard