6

Is it possible to bind a function to another function on invoke? So for example, it would go something like this:

function a(){...}
function b(){...}
b.bind("onInvoke","a");

So when b is called, a is also automatically called.


EDIT: OK OK, to clarify, this is not a question on chaining. The idea is to find an elegant way to do event binding. Observe the normal "non-elegant" way with normal function call-back:

function handler(){...}
function caller1(){handler(); ...}
function caller2(){handler(); ...}
function caller2(){handler(); ...}
// More callers all over your website everywhere else

That works right? But what if I have caller all over the place? It's hard to organize or change things.

Now observe the superior solution! (If one exist)

function handler(){...}
// Caller make no reference to handler on creation
function caller1(){...}
function caller2(){...}
function caller3(){...}
// Caller function are still all over the place, all over your website
// Event handler registered later in one location here, doesn't matter where they are phsically
caller1.bind("onInvoke",handler);
caller2.bind("onInvoke",handler);
caller3.bind("onInvoke",handler);

So very much like your normal HTML - JQuery event registration. You don't write onClick on every image the user might click on (which are all over the place), it would be way too troublesome to organize that! You just write one simple

 $("img").bind("onClick",click_handler);

for your entire site. This is the jist of what I am looking for, except for JS functions.

I hope that clarify things.


EDIT 2: Need to work with IE7!!! JavaScript 1.8.5 is great and everything, but nothing support it right now.

5
  • possible duplicate of Can I intercept a function called directly?
    – Andy E
    Commented Dec 7, 2011 at 20:49
  • @AndyE I get the feeling the OP is more interested in a solution to automatically call functions in sequence.
    – Peter
    Commented Dec 7, 2011 at 21:25
  • @Peter: I'm not so sure. "So when b is called, a is also automatically called." — there's potentially a difference in execution order (this question may want a to be invoked after b, for instance), but the premise between the two questions appears to be the same; "when a function is called, call this other function". I could be wrong, but it's up to the OP to make a clear distinction between the two questions :-)
    – Andy E
    Commented Dec 7, 2011 at 21:30
  • @AndyE, sure, I agree the OP should clarify! I just got that feeling from his bind example. Even so, that question is likely a duplicate too :D
    – Peter
    Commented Dec 7, 2011 at 21:42
  • For those who are reading this later. Both Adam Rackis and Simon solution seem to work. Simon's solution is superior because it allow multiple function to be binded. Commented Dec 8, 2011 at 14:54

4 Answers 4

4

You can do that with an aspect-oriented approach. Here is a simple example:

Attach call to a() to function b():

var _b = b;
b = function(){
   _b();
   a();
}

Now call b():

b();

See it in action here: http://jsfiddle.net/eZ9wJ/

7
  • In this example b is a global variable. You should alway use var for defining variables; Commented Dec 7, 2011 at 20:59
  • 2
    I'm overwriting the reference to the global function b() that Yongke already defined in the code in his question. To invoke function a() on any call to b(), you have to overwrite it in the same scope in which the original function has been defined. Of course this is just a simplified example. In a real example, I wouldn't recommend to define the function in the global scope.
    – Simon
    Commented Dec 7, 2011 at 21:03
  • 2
    One thing to keep in mind here is that any object that was intially holding onto a reference to b will not be updated; thus this approach could break. It should be emphasized that we are still calling a new function here, even though we store it in the original variable.
    – Peter
    Commented Dec 7, 2011 at 21:16
  • Hi Simon, nice solution, can you wrap everything in a convenient "bind" function or is that not possible with this setup. Commented Dec 8, 2011 at 13:29
  • Well, using closures, you can create something that comes quite close to a convenient bind function: jsfiddle.net/WQn6p . This fiddle also shows how passing arguments to the bound function works.
    – Simon
    Commented Dec 8, 2011 at 14:08
2

There are various solutions depending on how much you want to architect. A simple and flexible approach is to create a chaining utility function:

function chain() {
   var args = arguments;
   return function() {
      // loop through arguments and invoke all functions
      for(var i = 0; i < args.length; i++) {
         if(typeof args[i] == "function")
            args[i]();
      }
   }
}

What this is doing is returning a new function that will call the provided functions in sequence. Use it like this:

var myChain = chain(b, a);
myChain();
2
  • Hi Peter, this solution is good for chaining but not useful under the situation I am currently in. Commented Dec 8, 2011 at 13:30
  • @YongkeBillYu: Actually, it does solve your problem. Just do caller1 = chain(handler, caller1)
    – hugomg
    Commented Dec 8, 2011 at 14:01
0

You can use callback:

function a(){
  // some code here
  b();
}
function b(){...}

Or observer pattern - http://www.michaelhamrah.com/blog/2008/12/event-pooling-with-jquery-using-bind-and-trigger-managing-complex-javascript/

1
  • Using this code, this's reference is not preserved, neither the function arguments.
    – Rob W
    Commented Dec 7, 2011 at 20:56
0

JavaScript 1.8.5 / ECMAScript 5 does indeed define a bind function, but it doesn't do what you describe above; it allows you to specify what the this context will be when it is invoked, and, optionally, allows you to hard-code certain arguments—curry.

1
  • I assume not much browser support currently exist for JS 1.8.5 right? Commented Dec 8, 2011 at 13:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.