How to execute a JavaScript function when I have its name as a string
JavascriptJavascript Problem Overview
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[...])
.
Javascript Solutions
Solution 1 - Javascript
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);
Solution 2 - Javascript
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);
}
Solution 3 - Javascript
The answer to this other question shows you how to do that: https://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.
Solution 4 - Javascript
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);
Solution 5 - Javascript
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.
Solution 6 - Javascript
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
Solution 7 - Javascript
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 throughx.y['foo']()
orx['y']['foo']()
or evenwindow['x']['y']['foo']()
. You can chain indefinitely like this.
Solution 8 - Javascript
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
https://stackoverflow.com/questions/9464921/dynamically-call-local-function-in-javascript
Solution 9 - 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"]()
Solution 10 - Javascript
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.
Solution 11 - Javascript
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
*/
Solution 12 - Javascript
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"]()
Solution 13 - Javascript
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.
Solution 14 - Javascript
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
Solution 15 - Javascript
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);
Solution 16 - Javascript
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.
Solution 17 - Javascript
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');
Solution 18 - Javascript
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 ...
Solution 19 - Javascript
One more detail on Jason and Alex's posts. I found it helpful to add a default value to context. Just put context = context == undefined? window:context;
at the beginning of the function. You can change window
to whatever your preferred context is, and then you won't need to pass in the same variable each time you call this in your default context.
Solution 20 - Javascript
To add to Jason Bunting's answer, if you're using nodejs or something (and this works in dom js, too), you could use this
instead of window
(and remember: eval is evil:
this['fun'+'ctionName']();
Solution 21 - Javascript
There's a very similar thing in my code. I have a server-generated string which contains a function name which I need to pass as a callback for a 3rd party library. So I have a code that takes the string and returns a "pointer" to the function, or null if it isn't found.
My solution was very similar to "Jason Bunting's very helpful function" *, although it doesn't auto-execute, and the context is always on the window. But this can be easily modified.
Hopefully this will be helpful to someone.
/**
* Converts a string containing a function or object method name to a function pointer.
* @param string func
* @return function
*/
function getFuncFromString(func) {
// if already a function, return
if (typeof func === 'function') return func;
// if string, try to find function or method of object (of "obj.func" format)
if (typeof func === 'string') {
if (!func.length) return null;
var target = window;
var func = func.split('.');
while (func.length) {
var ns = func.shift();
if (typeof target[ns] === 'undefined') return null;
target = target[ns];
}
if (typeof target === 'function') return target;
}
// return null if could not parse
return null;
}
Solution 22 - Javascript
Here's a bit robust and reusable solution I ended up implementing for one of my projects.
A FunctionExecutor Constructor Function
Usage:
let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)
executor.execute("one");
executor.execute("three");
Obviously in the project the adding of all the functions that required to be called by name was done by a loop.
The function Executor:
function FunctionExecutor() {
this.functions = {};
this.addFunction = function (fn) {
let fnName = fn.name;
this.functions[fnName] = fn;
}
this.execute = function execute(fnName, ...args) {
if (fnName in this.functions && typeof this.functions[fnName] === "function") {
return this.functions[fnName](...args);
}
else {
console.log("could not find " + fnName + " function");
}
}
this.logFunctions = function () {
console.log(this.functions);
}
}
Example Usage:
function two() {
console.log("two");
}
function three() {
console.log("three");
}
let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)
executor.execute("one");
executor.execute("three");
Solution 23 - Javascript
There too some very helpful way.
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
var arrayMaker = {
someProperty: 'some value here',
make: function (arg1, arg2) {
return [ this, arg1, arg2 ];
},
execute: function_name
};
Solution 24 - Javascript
I can't resist mentioning another trick, which helps if you have an unknown number of arguments that are also being passed as part of the string containing the function name. For example:
var annoyingstring = 'call_my_func(123, true, "blah")';
If your Javascript is running on a HTML page, all you need is an invisible link; you can pass a string into the onclick
attribute, and the call the click
method.
<a href="#" id="link_secret"><!-- invisible --></a>
$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();
Or create the <a>
element at runtime.
Solution 25 - Javascript
Easiest way is to access it like has element
window.ClientSideValidations.forms.location_form
is same as
window.ClientSideValidations.forms['location_form']
Solution 26 - Javascript
People keep saying that eval
is dangerous and evil because it can run any arbitrary code. However, if you use eval with a whitelisting approach, assuming you know all the possible function names that may need to be run in advance, then eval is no longer a security concern because the input is no longer arbitrary. Whitelisting is a good and frequent security pattern. Here's an example:
function runDynamicFn(fnName, ...args) {
// can also be fed from a tightly controlled config
const allowedFnNames = ['fn1', 'ns1.ns2.fn3', 'ns4.fn4'];
return allowedFnNames.includes(fnName) ? eval(fnName)(...args) : undefined;
}
// test function:
function fn1(a) {
console.log('fn1 called with', a)
}
runDynamicFn('alert("got you!")')
runDynamicFn('fn1', 'foo')
Solution 27 - Javascript
This is working for me:
var command = "Add";
var tempFunction = new Function("Arg1","Arg2", "window." + command + "(Arg1,Arg2)");
tempFunction(x,y);
I hope this works.
Solution 28 - Javascript
Look basic:
var namefunction = 'jspure'; // String
function jspure(msg1 = '', msg2 = '') {
console.log(msg1+(msg2!=''?'/'+msg2:''));
} // multiple argument
// Results ur test
window[namefunction]('hello','hello again'); // something...
eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple
Exist other type function is class and look example nils petersohn
Solution 29 - Javascript
Thanks for the very helpful answer. I'm using Jason Bunting's function in my projects.
I extended it to use it with an optional timeout, because the normal way to set a timeout wont work. See abhishekisnot's question
function executeFunctionByName(functionName, context, timeout /*, args */ ) {
var args = Array.prototype.slice.call(arguments, 3);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
var timeoutID = setTimeout(
function(){ context[func].apply(context, args)},
timeout
);
return timeoutID;
}
var _very = {
_deeply: {
_defined: {
_function: function(num1, num2) {
console.log("Execution _very _deeply _defined _function : ", num1, num2);
}
}
}
}
console.log('now wait')
executeFunctionByName("_very._deeply._defined._function", window, 2000, 40, 50 );
Solution 30 - Javascript
There are several executeByName
functions here which works fine, unless name contains square brackets - issue I ran into - as I have dynamically generated names. So above functions will fail on names like
app.widget['872LfCHc']['toggleFolders']
As a remedy, I've made function to take this into account too, maybe someone will find it usefull:
Generated from CoffeeScript:
var executeByName = function(name, context) {
var args, func, i, j, k, len, len1, n, normalizedName, ns;
if (context == null) {
context = window;
}
args = Array.prototype.slice.call(arguments, 2);
normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.');
ns = normalizedName.split(".");
func = context;
for (i = j = 0, len = ns.length; j < len; i = ++j) {
n = ns[i];
func = func[n];
}
ns.pop();
for (i = k = 0, len1 = ns.length; k < len1; i = ++k) {
n = ns[i];
context = context[n];
}
if (typeof func !== 'function') {
throw new TypeError('Cannot execute function ' + name);
}
return func.apply(context, args);
}
For better readability check also CoffeeScript version:
executeByName = (name, context = window) ->
args = Array.prototype.slice.call(arguments, 2)
normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.')
ns = normalizedName.split "."
func = context
for n, i in ns
func = func[n]
ns.pop()
for n, i in ns
context = context[n];
if typeof func != 'function'
throw new TypeError 'Cannot execute function ' + name
func.apply(context, args)
Solution 31 - Javascript
You can call javascript function within the eval("functionname as string")
either. Like below: (eval is pure javascript function)
function testfunc(){
return "hello world";
}
$( document ).ready(function() {
$("div").html(eval("testfunc"));
});
Working example: https://jsfiddle.net/suatatan/24ms0fna/4/
Solution 32 - Javascript
all you have to do is use a context or define a new context where you function(s) reside.
you are not limited to window["f"]();
here is an example of how I use some dynamic invocation for some REST services.
/*
Author: Hugo Reyes
@ www.teamsrunner.com
*/
(function ( W, D) { // enclose it as self invoking function to avoid name collisions.
// to call function1 as string
// initialize your FunctionHUB as your namespace - context
// you can use W["functionX"](), if you want to call a function at the window scope.
var container = new FunctionHUB();
// call a function1 by name with one parameter.
container["function1"](' Hugo ');
// call a function2 by name.
container["function2"](' Hugo Leon');
// OO style class
function FunctionHUB() {
this.function1 = function (name) {
console.log('Hi ' + name + ' inside function 1')
}
this.function2 = function (name) {
console.log('Hi' + name + ' inside function 2 ')
}
}
})(window, document); // in case you need window context inside your namespace.
If you want to generate the entire function from a string, that's a different answer.
also please notice that you are not limited to a single name space, if you name space exists as my.name.space.for.functions.etc.etc.etc
the last branch of your name space contains the function as my.name.space.for.functions.etc.etc["function"]();
Hope it helps. H.
Solution 33 - Javascript
Since eval()
is evil, and new Function()
is not the most efficient way to achieve this, here is a quick JS function that returns the function from its name in string.
- Works for namespace'd functions
- Fallbacks to null-function in case of null/undefined string
- Fallbacks to null-function if function not found
function convertStringtoFunction(functionName){
var nullFunc = function(){}; // Fallback Null-Function
var ret = window; // Top level namespace
// If null/undefined string, then return a Null-Function
if(functionName==null) return nullFunc;
// Convert string to function name
functionName.split('.').forEach(function(key){ ret = ret[key]; });
// If function name is not available, then return a Null-Function else the actual function
return (ret==null ? nullFunc : ret);
}
Usage:
convertStringtoFunction("level1.midLevel.myFunction")(arg1, arg2, ...);
Solution 34 - Javascript
You may place your functions names in an Array object and then call the array key respective to each function to execute it, DEMO:
function captchaTest(msg){
let x = Math.floor(Math.random()*(21-1)) +1;
let y = Math.floor(Math.random()*(11-1)) +1;
let sum = function(){
return x+y;
}
let sub = function(){
if (y > x){
let m = y;
y = x;
x = m;
console.log(x,y,m,'--')
}
return x-y;
}
let mul = function(){
return x*y;
}
let OParr = [sum(), sub(), mul()];
let OP = Math.floor(Math.random()*OParr.length);
let s = OParr[OP]; //!!! HERE !!! is the call as array element
switch(OP){
case 0:
opra = '+';
break;
case 1:
opra = '━';
break;
default:
opra = '✖';
}
let msg2 = 'Answer the following question to continue:'
let p = prompt(msg+' '+msg2+'\n'+'What is the result of '+x+opra+y+' ?','')
console.log(s,p,OP)
if (s == p){
alert ('Wow, Correct Answer!')
return true;
}
else{
alert('Sorry, the answer is not correct!')
return false;
}
}
Solution 35 - Javascript
Without using eval('function()')
you could to create a new function using new Function(strName)
. The below code was tested using FF, Chrome, IE.
<html>
<body>
<button onclick="test()">Try it</button>
</body>
</html>
<script type="text/javascript">
function test() {
try {
var fnName = "myFunction()";
var fn = new Function(fnName);
fn();
} catch (err) {
console.log("error:"+err.message);
}
}
function myFunction() {
console.log('Executing myFunction()');
}
</script>