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.
Some of the functions may take the form of namespace.namespace.function(args[...])
.
There are two methods to call a function from string stored in a variable. The first one is by using the window object method and the second one is by using eval() method. The eval() method is older and it is deprecated.
Use the eval() method to create a function from the string. It accepts the function in the form of string and converts it to JavaScript function.
Define a function named "myFunction", and make it display "Hello World!" in the <p> element. Hint: Use the function keyword to define the function (followed by a name, followed by parentheses). Place the code you want executed by the function, inside curly brackets. Then, call the function.
To convert a string in to function "eval()" method should be used. This method takes a string as a parameter and converts it into a function.
Just thought I'd post a slightly altered version of Jason Bunting's very helpful function.
First, I have simplified the first statement by supplying a second parameter to slice(). The original version was working fine in all browsers except IE.
Second, I have replaced this with context in the return statement; otherwise, this was always pointing to window when the target function was being executed.
function executeFunctionByName(functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments, 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(context, args);
}
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, 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(context, 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);
The answer to this other question shows you how to do that: Javascript equivalent of Python's 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.
I think an elegant way of doing this is by defining your functions in a hash object. Then you can have a reference to those functions from the hash using the string. e.g.
var customObject = {
customFunction: function(param){...}
};
Then you can call:
customObject['customFunction'](param);
Where customFunction will be a string matching a function defined in your object.
UPDATE
It seems that this answer was helpful for many fellow coders out there so here goes an updated version.
With ES6 you can additionally use Computed Property Names which will allow you to avoid magic strings.
const FunctionNames = Object.freeze({
FirstFunction: "firstFunction",
SecondFunction: "secondFunction"
});
...
var customObject = {
[FunctionNames.FirstFunction]: function(param){...},
[FunctionNames.SecondFunction]: function(param){...}
};
...
customObject[FunctionNames.FirstFunction](param);
Could you not just do this:
var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();
You can also execute any other JavaScript using this method.
With ES6 you could to access class methods by name:
class X {
method1(){
console.log("1");
}
method2(){
this['method1']();
console.log("2");
}
}
let x = new X();
x['method2']();
the output would be:
1
2
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.
All the answers assume that the functions can be accessed through global scope (window). However, the OP did not make this assumption.
If the functions live in a local scope (aka closure) and are not referenced by some other local object, bad luck: You have to use eval()
AFAIK, see
dynamically call local function in javascript
Depending on where you are you can also use:
this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();
or, in nodejs
global["funcname"]()
You just need convert your string to a pointer by window[<method name>]
.
example:
var function_name = "string";
function_name = window[function_name];
and now you can use it like a pointer.
Here is my contribution to Jason Bunting's / Alex Nazarov's excellent answers, where I include error checking requested by Crashalot.
Given this (contrived) preamble:
a = function( args ) {
console.log( 'global func passed:' );
for( var i = 0; i < arguments.length; i++ ) {
console.log( '-> ' + arguments[ i ] );
}
};
ns = {};
ns.a = function( args ) {
console.log( 'namespace func passed:' );
for( var i = 0; i < arguments.length; i++ ) {
console.log( '-> ' + arguments[ i ] );
}
};
name = 'nsa';
n_s_a = [ 'Snowden' ];
noSuchAgency = function(){};
then the following function:
function executeFunctionByName( functionName, context /*, args */ ) {
var args, namespaces, func;
if( typeof functionName === 'undefined' ) { throw 'function name not specified'; }
if( typeof eval( functionName ) !== 'function' ) { throw functionName + ' is not a function'; }
if( typeof context !== 'undefined' ) {
if( typeof context === 'object' && context instanceof Array === false ) {
if( typeof context[ functionName ] !== 'function' ) {
throw context + '.' + functionName + ' is not a function';
}
args = Array.prototype.slice.call( arguments, 2 );
} else {
args = Array.prototype.slice.call( arguments, 1 );
context = window;
}
} else {
context = window;
}
namespaces = functionName.split( "." );
func = namespaces.pop();
for( var i = 0; i < namespaces.length; i++ ) {
context = context[ namespaces[ i ] ];
}
return context[ func ].apply( context, args );
}
will allow you to call a javascript function by name stored in a string, either namespaced or global, with or without arguments (including Array objects), providing feedback on any errors encountered (hopefully catching them).
The sample output shows how it works:
// calling a global function without parms
executeFunctionByName( 'a' );
/* OUTPUT:
global func passed:
*/
// calling a global function passing a number (with implicit window context)
executeFunctionByName( 'a', 123 );
/* OUTPUT:
global func passed:
-> 123
*/
// calling a namespaced function without parms
executeFunctionByName( 'ns.a' );
/* OUTPUT:
namespace func passed:
*/
// calling a namespaced function passing a string literal
executeFunctionByName( 'ns.a', 'No Such Agency!' );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
*/
// calling a namespaced function, with explicit context as separate arg, passing a string literal and array
executeFunctionByName( 'a', ns, 'No Such Agency!', [ 007, 'is the man' ] );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
-> 7,is the man
*/
// calling a global function passing a string variable (with implicit window context)
executeFunctionByName( 'a', name );
/* OUTPUT:
global func passed:
-> nsa
*/
// calling a non-existing function via string literal
executeFunctionByName( 'n_s_a' );
/* OUTPUT:
Uncaught n_s_a is not a function
*/
// calling a non-existing function by string variable
executeFunctionByName( n_s_a );
/* OUTPUT:
Uncaught Snowden is not a function
*/
// calling an existing function with the wrong namespace reference
executeFunctionByName( 'a', {} );
/* OUTPUT:
Uncaught [object Object].a is not a function
*/
// calling no function
executeFunctionByName();
/* OUTPUT:
Uncaught function name not specified
*/
// calling by empty string
executeFunctionByName( '' );
/* OUTPUT:
Uncaught is not a function
*/
// calling an existing global function with a namespace reference
executeFunctionByName( 'noSuchAgency', ns );
/* OUTPUT:
Uncaught [object Object].noSuchAgency is not a function
*/
If you want to call a function of an object instead of a global function with window["functionName"]
. You can do it like;
var myObject=new Object();
myObject["functionName"](arguments);
Example:
var now=new Date();
now["getFullYear"]()
BE CAREFUL!!!
One should try to avoid calling a function by string in JavaScript for two reasons:
Reason 1: Some code obfuscators will wreck your code as they will change the function names, making the string invalid.
Reason 2: It is much harder to maintain code that uses this methodology as it is much harder to locate usages of the methods called by a string.
Here is my Es6 approach which enables you to call your function by it's name as string or it's function name and also enable you to pass different numbers of arguments to different types of functions:
function fnCall(fn, ...args)
{
let func = (typeof fn =="string")?window[fn]:fn;
if (typeof func == "function") func(...args);
else throw new Error(`${fn} is Not a function!`);
}
function example1(arg1){console.log(arg1)}
function example2(arg1, arg2){console.log(arg1 + " and " + arg2)}
function example3(){console.log("No arguments!")}
fnCall("example1", "test_1");
fnCall("example2", "test_2", "test3");
fnCall(example3);
fnCall("example4"); // should raise an error in console
Surprised to see no mention of setTimeout.
To run a function without arguments:
var functionWithoutArguments = function(){
console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);
To run function with arguments:
var functionWithArguments = function(arg1, arg2) {
console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");
To run deeply namespaced function:
var _very = {
_deeply: {
_defined: {
_function: function(num1, num2) {
console.log("Execution _very _deeply _defined _function : ", num1, num2);
}
}
}
}
setTimeout("_very._deeply._defined._function(40,50)", 0);
I don't think you need complicated intermediate functions or eval or be dependent on global variables like window:
function fun1(arg) {
console.log(arg);
}
function fun2(arg) {
console.log(arg);
}
const operations = {
fun1,
fun2
};
operations["fun1"]("Hello World");
operations.fun2("Hello World");
// You can use intermediate variables, if you like
let temp = "fun1";
operations[temp]("Hello World");
It will also work with imported functions:
// mode.js
export function fun1(arg) {
console.log(arg);
}
export function fun2(arg) {
console.log(arg);
}
// index.js
import { fun1, fun2 } from "./mod";
const operations = {
fun1,
fun2
};
operations["fun1"]("Hello World");
operations["fun2"]("Hello World");
Since it is using property access, it will survive minimization or obfuscation, contrary to some answers you will find here.
So, like others said, definitely the best option is:
window['myfunction'](arguments)
And like Jason Bunting said, it won't work if the name of your function includes an object:
window['myobject.myfunction'](arguments); // won't work
window['myobject']['myfunction'](arguments); // will work
So here's my version of a function that will execute all functions by name (including an object or not):
my = {
code : {
is : {
nice : function(a, b){ alert(a + "," + b); }
}
}
};
guy = function(){ alert('awesome'); }
function executeFunctionByName(str, args)
{
var arr = str.split('.');
var fn = window[ arr[0] ];
for (var i = 1; i < arr.length; i++)
{ fn = fn[ arr[i] ]; }
fn.apply(window, args);
}
executeFunctionByName('my.code.is.nice', ['arg1', 'arg2']);
executeFunctionByName('guy');
let t0 = () => { alert('red0') }
var t1 = () =>{ alert('red1') }
var t2 = () =>{ alert('red2') }
var t3 = () =>{ alert('red3') }
var t4 = () =>{ alert('red4') }
var t5 = () =>{ alert('red5') }
var t6 = () =>{ alert('red6') }
function getSelection(type) {
var evalSelection = {
'title0': t0,
'title1': t1,
'title2': t2,
'title3': t3,
'title4': t4,
'title5': t5,
'title6': t6,
'default': function() {
return 'Default';
}
};
return (evalSelection[type] || evalSelection['default'])();
}
getSelection('title1');
A more OOP solution ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With