views:

5835

answers:

4

Hi,

I have the name of a function in JavaScript as a string, how do I convert that into a function pointer so I can call it later?

Depending on the circumstances I may need to pass various arguments into the method too...

EDIT I should note that some of the functions may take the form of namespace.namespace.function(args[...]);...

+5  A: 

The answer to this other question shows you how to do that: http://stackoverflow.com/questions/39960/javascript-locals

Basically, you can say

window["foo"](arg1, arg2);

or as many others have suggested, you can just use eval:

eval(fname)(arg1, arg2);

although this is extremely unsafe unless you're absolutely sure about what you're eval-ing.

Eli Courtwright
the first form is far preferable
annakata
Only use eval as a last resort, when all else fails.
Jason Bunting
It is...but will it work with functions like this: x.y.z(args)?
Kieron
@keiron: yes. see my answer below
annakata
+1  A: 

Two things:

  • avoid eval, it's terribly dangerous and slow

  • secondly it doesn't matter where your function exists, "global" -ness is irrelevant. x.y.foo() can be enabled through x.y['foo']() or x['y']['foo']() or even window['x']['y']['foo'](). You can chain indefinitely like this.

I <3 JS

annakata
but you can't do window['x.y.z']() to call x.y.z()
nickf
no, nickf, you can't do that. My answer provides a generic solution...
Jason Bunting
+20  A: 

Don't use eval unless you absolutely, positively have no other choice.

As has been mentioned, using something like this would be the best way to do it:

window["functionName"](arguments);

That, however, will not work with a namespace'd function:

window["My.Namespace.functionName"](arguments); // fail

This is how you would do that:

window["My"]["Namespace"]["functionName"](arguments); // succeeds

In order to make that easier and provide some flexibility, here is a convenience function:

function executeFunctionByName(functionName, context /*, args */) {
  var args = Array.prototype.slice.call(arguments).splice(2);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(this, args);
}

You would call it like so:

executeFunctionByName("My.Namespace.functionName", window, arguments);

Note, you can pass in whatever context you want, so this would do the same as above:

executeFunctionByName("Namespace.functionName", My, arguments);

Hope that helps...


EDIT: Changed function name to be a bit more generic.

Jason Bunting
you know you don't need the whole "func" construct? "context.apply" alone is fine
annakata
Sure, I know that - but the way I wrote the function provides some clarity for those reading it that may not completely grok what is happening. I wrote this function realizing people reading it may need some help. I will provide an alternate though, since you asked...
Jason Bunting
Scratch that - the code is clear enough and those that know, know. If you are like me, and know what you are doing, you can just make such changes on your own if you used this code. Stack Overflow is for educating others, and I think my code is easier for the novice to understand. Thanks though!
Jason Bunting
That's excellent, worked brilliantly - thanks for the effort!
Kieron
Is there a situation when window["funcName"] would return undefined? That is the problem I'm having at the moment.The calling code and the function are defined in two separate js files. I tried adding them to the same file but that made no difference.
A: 

I need that too.

This seems to work when everything is defined at the top (window) level, but I've been unable to find the right syntax to make it work anywhere else. Anyone else know how to do that?...

// Define function...
function f(msg1,msg2) {
  alert(msg1+'\n'+msg2);
};

// Simulate function name existing within a string...
var a = 'f';

// Convert that string into a function ("pointer")
// by treating it as an array of one. Since arrays are just a
// special kind of object and all functions are objects, this
// makes the variable b reference the function 'f'...
var b = this[a];

// Execute function using the function "pointer"...
b('a is a '+typeof(a),'b is a '+typeof(b))
RobertC
If you have a question then ask a **question** , don't claim it is an **answer** to another question (related or otherwise).
David Dorward
Apologies. New here.
RobertC
Could find no way to add the info as a comment to any of the displayed "answers" (just tried again without success) but "Add Another Answer" button is very prominant.
RobertC
For Those Looking For An Extensive Article On This, Try... http://www.jibbering.com/faq/faq_notes/square_brackets.html
RobertC