I want a function that will call other functions. It may seem like a silly requirement, but I have a use for this functionality. One day, you may too. Initially thinking about the requirements I know what I don't know:
- I don't know the function name
- I don't know the number of parameters the function requires
- I don't know if the function is nested, or if so, how nested
- I don't know what scope I want the function called in
You might be thinking - "if you don't know any of that stuff, why would you even write a function to handle the situation". But strangely, you're still reading.
You can call functions that are variably named using the following syntax:


1<br /> 2 window['function'](parameters);<br />
The limitation of that calling structure is that it assumes the function to be called is a named function that is a child of the window object. There are a lot of situations where this is not the case. Fortunately, you can call nested functions similarly:


1<br /> 2 window['object name']['function'](parameters);<br />
In order to call nested functions with this syntax, you must know the depth of your function - i.e. how many sets of brackets do you need to define? An additional problem is that you are always only passing one parameter - this is a problem if you are calling a function that expects multiple parameters.
I'm going to start out with some poorly written code to demonstrate an arbitrarily complex object named arby:


1<br /> 2arby = new Object();<br /> 3arby.name = 'bill';<br /> 4arby.fred = 'barney';<br /> 5arby.al = new Object();<br /> 6arby.al.fonzie = 'richy';<br /> 7arby.al.func = function argsreport(args){<br /> 8 return 'arby.al.func : ' arguments.length;<br /> 9}<br /> 10arby.al.betty = new Object();<br /> 11arby.al.betty.func = function argsreport(args){<br /> 12 return 'arby.al.betty.func : ' arguments.length;<br /> 13}<br />
The arby object is an example of what I'm talking about - there are syntactical differences in the way you would call arby.al.func() and arby.al.betty.func(). ( window['arby']['al']['func'](pars) or window['arby']['al']['betty']['func'](pars) )
The solution to this problem is determining the depth of your function as part of your calling function or as a known piece of data. You can then iterate through a loop recursively assigning a variable to the next child element until you reach the desired syntax you are looking for.
To deal with the other problems - having an arbitrary number of parameters and binding a "this" object to the function - we use the Function.apply() method. Function.apply is part of the Function prototype, so it is available to every function that you write. It takes two parameters - the object with which you are binding, and an array based parameter list.
In action:


1<br /> 2function dofunction(opts,argies){<br /> 3 var depth = opts.depth;<br /> 4 var i = 0;<br /> 5 var myobj = window[opts.obj[i]];<br /> 6 i = i + 1;<br /> 7 while(depth > 1){<br /> 8 myobj = myobj[opts.obj[i]];<br /> 9 i++;<br /> 10 depth--;<br /> 11 }<br /> 12 if(typeof opts.binding == 'undefined'){<br /> 13 return myobj[opts.obj[i]].apply(undefined, opts.pars);<br /> 14 } else {<br /> 15 return myobj[opts.obj[i]].apply(opts.binding, opts.pars);<br /> 16 }<br /> 17} <br />
This can be called easily:


1<br /> 2console.log(dofunction(<br /> 3 {depth: 3, <br /> 4 obj:['arby','al','betty','func'],<br /> 5 pars:[1,2,3]}<br /> 6));<br /> 7//prints 'arby.al.betty.func : 3' to the console<br />
It's not rocket science, and most people would use 'eval' to get the job done. IMO, you should always avoid eval. Aside from that, this should run much quicker than eval.
For a real world example of why you might use a function like this you can think of the prototype.js library. You may want to call Element.hide, Ajax.Request, or a similar function from within a piece of code.
My own personal requirement stems from the KDF clientside framework, which if you've been following my progress (or lack thereof :) ) has a tertiary goal of limitless extensibility and this code is quite similar to one of the cornerstones that makes it tick.
Arbitrary Function Calls in Javascript Interaction
