Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript equivalent of php call_user_func

Tags:

javascript

I've found this topic which I've implemented (see accepted answer):
javascript equivalent of PHP's call_user_func()

However, I am having a problem with multiple parameters. I realize what I was doing was turning my parameters into strings and treating it like 1 parameter, but I don't know how to fix this because I am dynamically creating the parameters.

Meaning, I have defined in my code the following:

var a = new Array();
a[0] = new Array();
a[0][0] = 'alert';
a[0][1] = '\'Hello World\'';
a[1] = new Array();
a[1][0] = 'setTimeout';
a[1][1] = 'alert("goodbye world")';
a[1][2] = '20';

Later, I was calling them like this:

    var j = 0;
    var len = 0;
    var fx = '';
    var params = '';
    for( i in a ){
        params = '';
        len = a[i].length;
        fx = a[i][0]; // getting the function name
        a[i].splice( 0, 1 ); // removing it from array
        if( len > 1 ){
            params = a[i].join(", "); // trying to turn the parameters into the right format, but this is turning it into strings I think
            params = params.replace(/\\'/g,'\''); // bc i was adding slashes with PHP
        }
        window[fx](params);
    }

I don't have to use arrays to do this. I don't understand JS OOP (haven't tried yet), though I am comfortable with PHP OOP, so I don't know if there is a way to do this there.

Any help on passing multiple parameters would be appreciated.

Thanks.

like image 589
phpmeh Avatar asked Apr 08 '12 08:04

phpmeh


3 Answers

First thing to do: Scrap your entire code, start over. Your approach will not get you anywhere where you'd want to be. (Unfortunately I can't tell you where you'd want to be because I cannot make sense of your example.)

There are three ways to call a function in JavaScript.

function foo() { console.log(arguments); }

// 1. directly
foo(1, 2, 3);

// 2. trough Function.call()
foo.call(this, 1, 2, 3);

// 3. trough Function.apply()
var args = [1, 2, 3];
foo.apply(this, args);

call and apply are similar. They let you decide which object the this keyword will point to inside the function (that's the important bit!).

apply accepts an array of arguments, call accepts individual arguments.

The closest thing to call() is PHP's call_user_func(). The closest thing to apply() is PHP's call_user_func_array().

JavaScript objects share something with PHP arrays: They are key/value pairs.

// an anonymous function assigned to the key "foo"
var obj = {
  foo: function () { console.log(arguments); }
};

This means you can access object properties either with the dot notation:

// direct function call
obj.foo(1, 2, 3);

Or through square bracket notation (note that object keys are strings):

var funcName = "foo";
obj[funcName](1, 2, 3);
obj[funcName].call(obj, 1, 2, 3);
obj[funcName].apply(obj, [1, 2, 3]);

Square bracket notation gives you the freedom to choose an object property dynamically. If this property happens to be a function, apply() gives you the freedom to choose function arguments dynamically.

Every top-level function that has not been declared as the property of some object will become the property of the global object. In browsers the global object is window. (So the function foo() in my first code block above really is window.foo.)

Note that this does not work like in PHP. It will point to the object the function has been called on, not the object the function "belongs to". (The concept "belongs to" does not really exist in JavaScript. Things can be modeled that way, but it's only a convention.)

With direct calling (obj.foo(1, 2, 3)), this will point to obj. With call and apply, this will point to whatever object you want to. This is a lot more useful than it sounds at first. Most of the time when you want to call functions dynamically, you will end up using apply.

like image 51
Tomalak Avatar answered Oct 06 '22 00:10

Tomalak


Check out Function.apply:

function test(a, b) { console.log([a, b]) }

test.apply(null, [1, 2]); // => [ 1, 2 ]
like image 20
Pavel Strakhov Avatar answered Oct 05 '22 22:10

Pavel Strakhov


Late to the party, but now with ES6 you can simply do

function FunctionX(a,b,c,d){
    return a + b + c + d;
}

let fx = "FunctionX";
let params = [ 1, 10, 100, 200 ];

let answer = window[fx]( ... params);
let answer2 = globalThis[fx]( ... params );   // this is more cross-platform

to unpack your argument array

like image 20
Garet Claborn Avatar answered Oct 06 '22 00:10

Garet Claborn