I'm looking for a trick about this. I know how to call a dynamic, arbitrary function in Javascript, passing specific parameters, something like this:

function mainfunc (func, par1, par2){
    window[func](par1, par2);
}

function calledfunc(par1, par2){
    // Do stuff here
}

mainfunc('calledfunc','hello','bye');

I know how to pass optional, unlimited parameters using arguments[] collection inside mainfunc, but, I can't figure how to send an arbitrary number of parameters to mainfunc to be sent to calledfunc dynamically; how can I accomplish something like this, but with any number of optional arguments (not using that ugly if-else)? :

function mainfunc (func){
    if(arguments.length == 3)
        window[func](arguments[1], arguments[2]);
    elseif(arguments.length == 4)
        window[func](arguments[1], arguments[2], arguments[3]);
    elseif(arguments.length == 5)
        window[func](arguments[1], arguments[2], arguments[3], arguments[4]);
}

function calledfunc1(par1, par2){
    // Do stuff here
}

function calledfunc2(par1, par2, par3){
    // Do stuff here
}

mainfunc('calledfunc1','hello','bye');
mainfunc('calledfunc2','hello','bye','goodbye');

I apologize for my poor english, please ask me if you need some clarification about my (complicated) question.

Thanks in advance!

share|improve this question
2  
The PHP equivalent for apply() is call_user_func_array(). The phpjs.org/functions/call_user_func_array solution also uses it. – powtac Aug 25 '11 at 14:59

6 Answers

up vote 72 down vote accepted

Use the apply method of a function:-

function mainfunc (func){
    window[func].apply(null, Array.prototype.slice.call(arguments, 1));
}

Edit: It occurs to me that this would be much more useful with a slight tweak:-

function mainfunc (func){
    this[func].apply(this, Array.prototype.slice.call(arguments, 1));
}

This will work outside of the browser (this defaults to the global space). The use of call on mainfunc would also work:-

function target(a)
{
	alert(a)
}

var o = {suffix: " World",
		target : function(s) {
		alert(s + this.suffix);
	}
}

mainfunc("target", "Hello");

mainfunc.call(o, "target", "Hello");
share|improve this answer
4  
beat me to it :) developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/… for more detailed documentation – cobbal Mar 24 '09 at 9:57
Thanks for that link cobbal! I'm reading about (and discovering) apply method. – ARemesal Mar 24 '09 at 10:09
This is the most adequate solution, but in arguments it'll included the name of function (arguments[0]='func'). I can generate another array with all the arguments except the very first one, and then use this new array, but, are there any other solution which not using other array? – ARemesal Mar 24 '09 at 11:18
ARemesal, see my answer for a solution (using the first argument as the function name) – 999 Mar 24 '09 at 12:12
@ARemesal: Oops yes forgot to slice off the func parameter from the arguments. See my edit. – AnthonyWJones Mar 24 '09 at 13:18
show 2 more comments

Your code only works for global functions, ie. members of the window object. To use it with arbitrary functions, pass the function itself instead of its name as a string:

function dispatch(fn, args) {
    fn = (typeof fn == "function") ? fn : window[fn];  // Allow fn to be a function object or the name of a global function
    return fn.apply(this, args || []);  // args is optional, use an empty array by default
}

function f1() {}

function f2() {
    var f = function() {};
    dispatch(f, [1, 2, 3]);
}

dispatch(f1, ["foobar"]);
dispatch("f1", ["foobar"]);

f2();  // calls inner-function "f" in "f2"
dispatch("f", [1, 2, 3]);  // doesn't work since "f" is local in "f2"
share|improve this answer
1  
This works, but you should note it isn't what was asked for – Greg Mar 24 '09 at 12:04

You could use .apply()

You need to specify a this... I guess you could use the this within mainfunc.

function mainfunc (func)
{
    var args = new Array();
    for (var i = 1; i < arguments.length; i++)
        args.push(arguments[i]);

    window[func].apply(this, args);
}
share|improve this answer
arguments is not an array and has no member slice(). – Ferdinand Beyer Mar 24 '09 at 10:08
Oops, forgot about that - fixed – Greg Mar 24 '09 at 12:03
You don't need to convert 'arguments' to a REAL array. What's the point in this? It works perfectly without that step... – 999 Mar 24 '09 at 12:16
Not if you want to omit the first argument, which is the name of the function. – Ferdinand Beyer Mar 24 '09 at 12:18
Why not just use 'shift' then? (See my answer) – 999 Mar 24 '09 at 12:19
show 1 more comment

Here's what you need:

function mainfunc (){
    window[Array.prototype.shift.call(arguments)].apply(null, arguments);
}

The first argument is used as the function name and all of the remaining ones are used as arguments to the called function...

We're able to use the shift method to return and then delete the first value from the arguments array. Note that we've called it from the Array prototype since, strictly speaking, 'arguments' is not a real array and so doesn't inherit the shift method like a regular array would.


You can also call the shift method like this:

[].shift.call(arguments);
share|improve this answer
Thank you very much JimmyP, your solution is equivalent (after the edit) to the AnthonyWJones' one, and you gave me great tips and explanation about using Array.prototype and []. – ARemesal Mar 24 '09 at 14:09
Weird, I'm sure I tried this and got an error in IE – Greg Mar 24 '09 at 14:15

If you want to pass with "arguments" a few others, you have to create the array of all arguments together, i.e. like this:

var Log = {
    log: function() {
        var args = ['myarg here'];
        for(i=0; i<arguments.length; i++) args = args.concat(arguments[i]);
        console.log.apply(this, args);
    }
}
share|improve this answer

Couldn't you just pass the arguments array along?

function mainfunc (func){
    // remove the first argument containing the function name
    arguments.shift();
    window[func].apply(null, arguments);
}

function calledfunc1(args){
    // Do stuff here
}

function calledfunc2(args){
    // Do stuff here
}

mainfunc('calledfunc1','hello','bye');
mainfunc('calledfunc2','hello','bye','goodbye');
share|improve this answer
2  
No, you can't, since "arguments" is not an array but an array-like object and has no shift() member. You would need to copy the arguments 1 to arguments.length to a new array and pass that one to apply(). – Ferdinand Beyer Mar 24 '09 at 10:07

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

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