6

Does anyone know if there is one?

I want to call a function using a variable name.


edit:

I posted a fiddle here with what I'm trying to do:

http://jsfiddle.net/sAzPA/

<div id="some">
  ...
</div>

js:

(function($){
  $.fn.MyPlugin = function(){

    return this.each(function(){
       var somefunction = function(arg1, arg2){ alert(arg1); },
           someotherfunction = function(arg1, arg2){ alert(arg2); },
           reallyimportantfunction = function(arg1, arg2){
            var foo = $(this).attr('id') + 'function';

            // here I want to call the function with the foo value as name, and pass it arg1 and arg2

            $()[foo](arg1, arg2); // <- doesn't work

           };

       reallyimportantfunction();
    });
  };  
})(jQuery);


jQuery(function($){
  $('#some').MyPlugin ();

});
Alex
  • 66,732
  • 177
  • 439
  • 641

3 Answers3

18

If a function is defined at the global level, then it automatically becomes a child of the window object.

Therefore you can always call window.functionName(); any place you would normally just call functionName();.

Further, since in Javascript objects work like associative arrays, you can call any child of any object using array syntax like this: object['childName']. This includes functions, so you can do object['functionName'](); for any function which is a member of an object.

Combining these two points together, you can call any globally defined function like so:

window['functionName']();

And since functionName in the above example is a string, you can use a variable in those brackets, which means you've got the same functionality as PHP's call_user_func().

[EDIT]

As I stated, this works for any object. The OP's comments state that the functions he wants to use this way are in a JQuery plug-in. They are therefore likely to be part of the JQuery object, and would normally be called like so: JQuery().functionName(); (or with the $ in place of JQuery).

Javascript syntax allows us to use ['functionName']() in any place where we can use .functionName(), so therefore, taking the above JQuery example, we could change it to look like this:

JQuery()['functionName']();`

But this technique can be adapted for any Javascript object. Any place where you use .functionName(), it can be replaced with ['functionName']().

Spudley
  • 166,037
  • 39
  • 233
  • 307
  • the function (actually a set of functions) is a function variable inside a jquery plugin. I'm trying to call this function with parameters from a different function variable from the same plugin – Alex Apr 28 '11 at 12:27
  • @Alex: in that case, the functions you want are children of the JQuery object, so as per my answer above, you should be able to do `JQuery['functionName']();` – Spudley Apr 28 '11 at 12:29
  • @Alex: hmm. Actually, more likely `JQuery()['functionName']()`. But how would you normally call the function, ie if you were calling it normally? Any time you can use `.functionName()`, you can replace it with `['functionName']()`, so look at your current usage of the function, and adapt this technique to suit. – Spudley Apr 28 '11 at 12:38
  • if I would call it normally it would be `somefunction('bla', 'bla');` :) – Alex Apr 28 '11 at 12:40
  • well in that case, the original `window['functionName']()` example should work -- as so: `window['somefunction']('bla', 'bla');` – Spudley Apr 28 '11 at 12:44
  • Okay. In the example you've given, the function is declared within the scope of another function. It is therefore local scope, and not global scope. This means that the `window[]` option won't work, because it's not part of the `window` object. But the real problem you've got there is that `$(this).attr('id')+'function';` returns `undefinedfunction` because `this` is not the same object that you're expecting inside the closure. I've modified your fiddle so that `$(this)` works inside the closure and the functions have scope as well. It now works as you want it to: http://jsfiddle.net/RRvz2/1/ – Spudley Apr 28 '11 at 13:21
  • This seems to be encouraging globals :( – Warbo Aug 21 '14 at 16:04
  • Spudley, Your JQuery example includes a trailing char which you do not want in there. Correct version should be `JQuery()['functionName']();` – Average Joe Nov 17 '17 at 07:07
2

There are quite a few ways of achieving this. The quickest and the dirties (and unsafe!) way is to do (PS:fnName in the below examples is the name of the function stored as string)

eval(fnName)

However you can also do

            this[fnName]();//careful with "this" though. Try replacing with "window" if it doesnt work for you

or to call it by passing arguments

this[fnName].apply(contextObject,argumentArray) //contextObject will be objest which will be referenced by the keyword "this" within the function body (fnName's body), argumentArrayy is the array of arguments you want to pass to function.
Nikhil
  • 3,304
  • 1
  • 25
  • 42
  • 2
    Ehm, browser javascript is inherently unsafe. The client can alter the code at will. I would be a lot more scared of using the php `eval()`. Just make sure you check rigorously any data you submit, server-side. – gnud Apr 28 '11 at 12:13
  • that is quite true. However eval is much misunderstood. Most programmers immediately yell "EVIL!!!" as soon as they see eval whereas there are genuine cases where eval is very helpful and is recommended! – Nikhil Apr 28 '11 at 12:15
  • genuine cases yes, but they're few and far between. – Spudley Apr 28 '11 at 12:18
  • 1
    The browser's user is not the enemy; malicious users trying to do them harm are. We can prevent XSS by escaping user-provided data, but 'eval' can make that data harmful again! The more we use 'eval', the more chance a malicious user will find a way to get their data passed to it and hence bypass our XSS prevention. Also, "eval" can hinder code analysis, eg. asking an IDE to find all uses of a function. – Warbo Aug 21 '14 at 16:00
1
var a = function(foo) {console.log(foo);}

a.call(null, 'test');
a('test');
Emmerman
  • 2,371
  • 15
  • 9