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,030
  • 21
  • 100
  • 124
Nemoden
  • 8,396
  • 6
  • 38
  • 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

3 Answers3

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
  • 135,475
  • 25
  • 268
  • 257
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,609
  • 17
  • 17
  • +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,097
  • 13
  • 76
  • 95
  • `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