21

I've seen this technique for calling a Javascript function based on the value of a string variable.

function foo() {
    alert('foo');
}

var test = 'foo';

window[test]();  //This calls foo()

Is this the accepted way to do it or is there a better way? Any cross-browser issues to worry about?

Mark Biek
  • 146,731
  • 54
  • 156
  • 201

5 Answers5

37

Looks fine to me. I would probably create a simple helper function like following:

function runFunction(name, arguments)
{
    var fn = window[name];
    if(typeof fn !== 'function')
        return;

    fn.apply(window, arguments);
}

//If you have following function

function foo(msg)
{
    alert(msg);
}

//You can call it like

runFunction('foo', ['test']); //alerts test.
SolutionYogi
  • 31,807
  • 12
  • 70
  • 78
  • +1, beat me to it and had a better caller function. – TJ L Jul 17 '09 at 16:25
  • Good answer. I think having a helper that does some sanity checking is a great idea. – Mark Biek Jul 17 '09 at 16:31
  • 2
    How often would you call a function declared at the global scope and give it a context other than null? (btw I think your use of the word scope is misleading, context would be better) – AnthonyWJones Jul 17 '09 at 16:38
  • I thought long and hard about it and you are right, there won't be a situation where I would need to pass scope to the global function, will modify the code. – SolutionYogi Jul 17 '09 at 16:49
  • Awesome function!. I modified the line (for my use) to have 'return fn.apply(window,arguments)' so that I can get a return as well. – Shoogle Jun 11 '13 at 12:17
  • Perhaps using `call` method. I tested and it seems that you can then parse more arguments. I tried: `fn.call(window, window, arguments);` which will create these arguments for the `foo` function: `[Window, Array[1]]`. If you try the same with `apply` you will not gain access to all of the parameters. – Netsi1964 Feb 14 '15 at 08:29
  • The helper method should also receive context. It may not always be `window` context. – YetAnotherBot Mar 19 '19 at 07:32
9

I personally wouldn't bother even with a helper function

  window[someKey]('test')

would be fine.

However I wouldn't general maintain a set of possible functions to call at the global scope anyway. Hence I would use a more general pattern:-

 obj[someKey]('test')

where obj may be this, a property of this or variable from a closure.

AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
2

You can simply use it like this... (of course substitute the strings with variables where needed)

document["getElementById"]("elementName")["style"]["border"] = "1PX SOLID GREEN";

Which is also easily/usually typed like this of course...

document.getElementById("elementName").style.border = "1PX SOLID GREEN";

Here's another multi-dimensional example...

var myObject = new Object();
myObject["myValue"]["one"] = "first value";
myObject["myValue"]["two"] = "second value";
alert(myObject["myValue"]["two"]); //outputs "second value"

Which could also be written as...

var myObject = new Object();
myObject["myValue"] = {one: "first value", two: "second value"};
alert(myObject["myValue"]["two"]); //outputs "second value"
0

You can use eval(str)

eval('foo();');

use this with extreme caution.

FabianCook
  • 20,269
  • 16
  • 67
  • 115
Gee
  • 175
  • 2
  • 1
    -1. There is no need to use eval here. – SolutionYogi Jul 17 '09 at 16:22
  • Did I understand the question wrong? why is eval wrong? – Gee Jul 17 '09 at 16:25
  • Using eval you invoke the Javascript parser and goodness knows what else that is need to take text and turn it into a set of instructions that can be executed. window['foo']() works so eval should be avoided in this case – AnthonyWJones Jul 17 '09 at 16:33
  • 1
    Generally speaking, you should avoid using eval as it starts JS interpreter to execute code specified to eval. Additionally, user wants to execute a function given he has a name of the function in a string variable. Your code doesn't really do that. – SolutionYogi Jul 17 '09 at 16:34
  • 1
    Using eval is frowned upon in the JavaScript for good reason. But its also a valid answer to the question. – Andreas Köberle Aug 29 '12 at 21:21
  • Avoid eval at all costs (think: eval is evil). -1 because OP already had an almost workable solution, and this suggestion is worse. – Shiraz Feb 14 '19 at 16:30
0

I have created a function to call a named function. It works both in browser and in Node.js. I have created a gist (https://gist.github.com/netsi1964/3f19bd96f2d6e18bd818) which also contains a small test. The fingerprint of the function is: callFunction(scope, fn, args). It sets the scope in the function to the specified scope, and defaults to window (in browser) and global (in Node.js). To answer your original request you would use it like this: callFunction(window, "foo",["test"])

Netsi1964
  • 3,244
  • 1
  • 27
  • 17