Get JavaScript function-object from its name as a string?
JavascriptJavascript Problem Overview
In JavaScript, if I have a string in a variable, is there a way to get a reference to the function object which has that matching name? Note that jQuery is available to me so I can use any of its helper methods also.
For example:
myFunction = function(){};
var func_name = "myFunction";
var myFunctionPtr = ??? //how to get the function from the name
Thanks
Javascript Solutions
Solution 1 - Javascript
if you know that its a global function you can use:
var functPtr = window[func_name];
//functPtr()
Otherwise replace window with the parent object containing the function.
Solution 2 - Javascript
I just did a quick test in Firebug and I was able to get the function from the name by simply eval()
ing the name... I feel dirty using eval()
, but it seems to get the job done here quite nicely.
var myFunctionPtr = eval(func_name);
Solution 3 - Javascript
This is never a preferred approach. Instead of keeping the function name in func_name
, you could have kept the reference to a function just as successfully in something like func_to_call
.
If you absolutely require to keep the function reference as a string, you would typically use a hash table to map an arbitrary name to a variable (JS has first-class functions which makes it possible)
myFunction = function(){};
var obj = {func_name: myFunction};
obj['func_name']();//executes the function
Fiddled (I don't know why, it's a such a tiny script :)
It was suggested that you use eval(func_name)
- however this could quickly get out of control because of JS scoping.
You have also declared your myFunction = function(){};
as a global variable. On one hand, it lets you reference it as window[func_name]
but on the other hand it pollutes the global scope.
Solution 4 - Javascript
this[func_name] should give you the function.
var myfunc = this[func_name];
myfunc();
Solution 5 - Javascript
It depends on where and how the function is (or isn't) declared.
If it's a global and not declared via let name = ...
or const name = ...
syntax (and it's not a class constructor declared with class
), you can check by looking for it as a property on the global object. (Those caveats are all ES2015 things; more below.) You can get a reference to the global object via this
in loose mode at global scope; browsers also give you a global called window
. So assuming a browser:
if (typeof window[func_name] === "function") {
// ....
}
If it might not be a global, but rather is just in scope because your code closes over it, or if it was created using one of those ES2015 mechanisms I mentioned, there's really no good way to check other than eval
:
if (eval("typeof " + func_name) === "function") {
// ....
}
Using eval
is a last resort, and you must only use it with strictly-controlled input. But when you have to, and you have strictly-controlled input, it's fine.
About the ES2015 caveats:
The new let
, const
, and class
are very interesting beasties: When used at global scope, they create globals, but they don't create properties on the global object. As of ES2015, although all properties of the global object are globals, not all globals are properties of the global object. It's all part of trying to rein in vastly-polluted global namespace and also bring greater security to the JavaScript binding model. (Now that we have true modules.)
So (note that this will only run in cutting-edge browsers):
// Global scope, in a browser (because I used `window` and `document.body`) that
// implements this aspect of ES2015 (as I write this, Firefox's SpiderMonkey
// doesn't, Chrome's V8 does on the latest Chrome; expect SpiderMonkey and IE
// to catch up pretty quick (didn't test IE Edge, maybe it's already there)
// Strict mode isn't required for this behavior, but for the moment V8 only
// supports the block-scoped constructs in strict mode.
"use strict";
let tbody = setup();
// Old-fashioned var: Creates a property on the global object, so
// we get "function, function"
var f1 = function() { /*...*/ };
result("var declaration", typeof f1, typeof window["f1"]);
// Function declaration: Creates a property on the global object, so
// "function, function"
function f2() {}
result("function declaration", typeof f2, typeof window["f2"]);
// `let` declaration: Doesn't create property on global object, so
// "function, undefined"
let f3 = function() { /*...*/ };
result("let declaration", typeof f3, typeof window["f3"]);
// `const` declaration: Doesn't create property on global object, so
// "function, undefined"
const f4 = function() { /*...*/ };
result("const declaration", typeof f4, typeof window["f4"]);
// `class` declaration: Doesn't create property on global object, so
// "function, undefined"
class C1 {}
result("class declaration", typeof C1, typeof window["C1"]);
function setup() {
document.body.insertAdjacentHTML(
"beforeend",
"<table>" +
"<thead>" +
"<tr><th>test</th><th>global</th><th>prop</th></tr>" +
"</thead>" +
"<tbody></tbody>" +
"</table>"
);
return document.body.querySelector("tbody");
}
function result(label, direct, win) {
tbody.insertAdjacentHTML(
"beforeend",
"<tr><td>" + [label, direct, win].join("</td><td>") + "</td></tr>"
);
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 4px 8px;
}
Output on cutting-edge browsers:
+----------------------+------------+-----------+ | test | global | prop | +----------------------+------------+-----------+ | var declaration | function | function | | function declaration | function | function | | let declaration | function | undefined | | const declaration | function | undefined | | class declaration | function | undefined | +----------------------+------------+-----------+
Note: Some transpilers don't enforce this rigorously, so if you see different results in transpiled code, don't be surprised.
Solution 6 - Javascript
A safe way to do is to sandbox the alleged function while testing its type:
function isFunction(expr) {
function sandboxTemplate() {
var window, document, alert; // etc.
try {
return typeof $expr$ == "function";
} catch (e) {
return false;
}
}
try {
var sandbox = new Function(
sandboxTemplate.toString().replace("$expr$", expr)
+ "return sandboxTemplate()");
return sandbox();
} catch (e) {
return false;
}
}
function test(expr) {
document.write("<div>\"" + expr + "\" <b>is "
+ (isFunction(expr) ? "" : "not ")
+ "</b>a function</div>");
}
/* Let's do some testing */
function realFunction() {
}
test("realFunction"); // exists!
test("notHere"); // non-existent
test("alert('Malicious')"); // attempt to execute malicious code!
test("syntax error {"); // attempt to blow us up!
The output:
- "realFunction" is a function
- "notHere" is not a function
- "alert('Malicious')" is not a function
- "syntax error {" is not a function
The sandboxing code could be written in a more concise manner but I like using "template" functions instead of embedding JS code as string literals.
And oh, this does it nicely without using eval
-- though one can argue that using a Function constructor is no different than an eval
.
Solution 7 - Javascript
Use eval:
myFunction = function(){};
var func_name = "myFunction";
var myFunctionPtr = eval(func_name);
Solution 8 - Javascript
found the function and then call them
autoCallBack : function(_action){
$(".module").each(function(){
var modulName = $(this).attr("id");
if( isFunction(modulName) ){
eval(modulName)();
}
});
}
isFunction : function(_functionName){
try {
eval(_functionName);
} catch (error) {
return false;
}
return true;
}
Solution 9 - Javascript
For NodeJs
Write your functions in a separate file and export them and use with name reference of that to call them, Like
// functions.js
var funcOne = function(){
console.log('function ONE called')
}
module.exports={
// name_exported : internal_name
funcOne : funcOne
}
Use function defined in functions.js in index.js :
// index.js
var methods = require('./functions.js') // path to functions.js
methods['funcOne']()
OUTPUT :
> node index.js
> function ONE called