5

My JavaScript code is barely an Ajax request that expects XML to be returned from back-end. The back-end can return execute_callback as one of XML tags like this:

<?xml version="1.0" encoding="windows-1251"?>
<response>
    <execute_callback>
        <function_name>someFunction</function_name>
    </execute_callback>
</response>

And everything is okay as far as you know the exact number of parameters this callback expects. But what if the back-end has returned

<?xml version="1.0" encoding="windows-1251"?>
<response>
    <execute_callback>
        <function_name>someFunction</function_name>
        <param>10.2</param>
        <param>some_text</param>
    </execute_callback>
    <execute_callback>
        <function_name>otherFunction</function_name>
        <param>{ x: 1, y: 2 }</param>
    </execute_callback>
</response>

How do I now pass parameters 10.2 and 'some_text' to someFunction and JSON { x: 1, y: 2 } to otherFunction?

I know an ugly solution (using function's arguments), but I am looking for a pretty one.

And before I forget: don't parse the XML for me - I can do that on my own :) All I need is somewhat of a trick to pass an arbitrary number of arguments to a function in JavaScript. If you know Python, I want:

def somefunc(x, y):
    print x, y
args = { 'x' : 1, 'y' : 2 }
somefunc(**args)

but in JavaScript.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nemoden
  • 8,816
  • 6
  • 41
  • 65
  • How do you tell the difference between a literal—such as 10.2 and "some text" — and an expression that needs to be evaluated, such as `{ x: 1, y: 2 }`? – RobG Jul 21 '11 at 01:47
  • @RobG this does not concerns question. Example is always just an example. First thought: I will pass `type` attribute to ``. It's not a problem at all to understand what type is returned. – Nemoden Jul 21 '11 at 03:31

4 Answers4

9

You can just pass them all into your function:

function someFunction(){
    for(i = 0; i < arguments.length; i++)
        alert(arguments[i]);
}

Javascript functions have an arguments array-like object, and it is syntactically correct to call a javascript function with any number of arguments.

someFunction(1, 2, 'test', ['test', 'array'], 5, 0);

is a valid call to that function.

Paul
  • 139,544
  • 27
  • 275
  • 264
6

You could refer to Function.apply. Assuming the callback functions are declared in global object (window in browser).

var callback_function = window[function_name];
if (callback_function) { // prevent from calling undefined functions
    callback_function.apply(window, params);  // params is an array holding all parameters
}
Ghostoy
  • 2,689
  • 19
  • 18
  • +1 - I think this is the best method, though likely should be protected by `if (window[function_name])...`. But how to tell literals from identifiers and expressions? I guess they are all passed as strings and the called function works it out. – RobG Jul 21 '11 at 01:49
  • Perfect. Exactly what I'm looking for. By the way, I prefer `if (typeof fn == 'function') {` – Nemoden Jul 21 '11 at 03:15
0

Instead of calling the function, reference your function as an element in an associative array by name:

var funcName = // parse your xml for function name
var params = new Array();
params[0] = 10.2; // from your parsed xml
params[1] = 'some text'; // also from your parsed xml

// functions are attached to some Object o:

o[funcName](params); // equivalent to o.funcName(params);

I wrote an example of the above here: http://jsbin.com/ewuqur/2/edit

Paul
  • 19,704
  • 14
  • 78
  • 96
  • `function somefunc(x,y) { alert(x+y); }` I want to pass ['a', 'b']. `somefunc.apply(window, ['a', 'b'])` -> "ab". `window['somefunc'](['a','b'])` -> "abundefined". Odd :-( – Nemoden Jul 21 '11 at 03:28
  • @Nemoden: That's not what I said to do. apply is not necessary. http://jsbin.com/ewuqur/2/edit – Paul Jul 21 '11 at 12:16
  • to use Function.apply is yet another approach and it works. I just compared it with your method which has produced unexpected result. – Nemoden Jul 22 '11 at 03:06
  • @Nemoden, your second example didn't work either. Why attach your functions to the global window object? It's a poor practice. I attach my functions to my own objects and limit scope and access through closures. – Paul Jul 22 '11 at 03:39
  • Sorry, I messed up with the code there. Just replace `window['somefunc'](['a','b'])` with `somefunc.apply(window, ['a', 'b'])`. I don't see any reason why I shouldn't attach my `javascript` functions to `window` object, except you've called it "poor practice", which I can't understand why, so I still don't consider it a strong reason. Why `checkEmail(str)` function, which validates is a string an email, for example, should be attached to some object, but not `window`? – Nemoden Jul 22 '11 at 04:13
  • http://icant.co.uk/articles/seven-rules-of-unobtrusive-javascript/#r6 http://stackoverflow.com/questions/1841916/how-to-avoid-global-variables-in-javascript http://www.slideshare.net/cheilmann/javascript-best-practices-1041724 Good luck. – Paul Jul 22 '11 at 04:46
  • understand, but OOP is good when it's good. I can overwrite your object as well. `x = { init : function() { alert('init!'); } }; x = 1`. I use objects when I need to. Common-purposes function should be attached to `window` object. Just my opinion. And I've never suffered from my approach. Still, I'm not `convinced`. I'm not stubborn though. Just need more strong argumentation rather then just "your functions can be overwritten". – Nemoden Jul 22 '11 at 04:57
0

2022 Answer: You can now (Firefox=2012, Chrome=2015, Safari=2016) do this with a rest parameter:

function someFunction(first, ...extra) {
    console.log(`You started with "${first}"`);
    extra.forEach(arg => console.log(arg));
}

someFunction(1, 2, 3);

As noted in Paul's answer, there's an implicit arguments object, but arguments has some limitations. Notably, arguments contains all arguments and isn't a real array while rest parameters are a true array and intentionally omit any previously named arguments. The above example uses Array.prototype.forEach(), which won't work on arguments.

See also spread syntax, introduced at the same time, for other uses of this dot-dot-dot-variable notation.

Adam Katz
  • 14,455
  • 5
  • 68
  • 83