Executing JavaScript Functions from String Names
Introduction
JavaScript is a flexible and powerful language, providing a variety of ways to do just about anything, like invoking functions. One of the more interesting and lesser-known methods is invoking a function when you only have its name as a string.
This Byte will take you through the process of invoking JavaScript functions from string names, and why you might want to do so.
JavaScript Function Invocation
Before we get into the details of invoking functions from string names, let's take a look at how to invoke basic JavaScript functions. In JS, functions are invoked by appending parentheses ()
to the function name. This can be done directly, as in myFunction()
, or indirectly, as in myObject.myMethod()
.
function sayHello() {
console.log("Hello, world!");
}
sayHello(); // Outputs: Hello, world!
Why Invoke Functions from String Names?
If you don't already have a well-thought-out scenario for doing this, you wonder why we'd want to do it at all. Well, there are a few scenarios where this can be handy.
For instance, you might be working with an API that returns a string indicating which function should be executed, like a remote procedure call (RPC). Or, you maybe you're developing a plugin system where plugins register their functions by name, and you need to call these functions dynamically.
In these cases, being able to invoke a function from its string name can be a powerful tool in your app.
Basic Method: Using the Window Object
The most basic way to invoke a function from a string name in JavaScript is to use the window
object. In a browser environment, all global JavaScript functions become methods of the window
object. So, you can access these functions as properties of window
using bracket notation.
Here's a simple example:
function greet() {
console.log("Hello, world!");
}
var functionName = "greet";
window[functionName](); // Outputs: Hello, world!
In this code, we're defining a function greet
, then storing its name as a string in the variable functionName
. We then use bracket notation to access this function as a property of window
and invoke it.
Note: This method only works for global functions in a browser environment. It won't work for local functions or in non-browser environments like Node.js.
Advanced Method: Using JavaScript's eval() Function
A more advanced (and controversial) method for invoking a function from a string name is to use JavaScript's eval()
function. The eval()
function takes a string of JavaScript code and executes it. This means you can construct a string representing the function call you want to make, and eval()
will execute it.
Here's how you might do this:
function greet() {
console.log("Hello, world!");
}
var functionName = "greet";
eval(functionName + "()"); // Outputs: Hello, world!
In this example, we're concatenating the string "()"
to the function name and passing the resulting string to eval()
. This causes eval()
to execute the function call as if it were a line of JavaScript code.
Note: Use eval()
with caution! Because it executes arbitrary JavaScript code, it can pose serious security risks if misused. Always validate and sanitize any input that you pass to eval()
.
Alternative Method: Using the Function Constructor
Another way to execute a function from a string name in JavaScript is by using the Function constructor. This method is a bit more advanced, but it offers a lot of flexibility.
Here's how it works:
let functionName = "sayHello";
let functionArguments = ["John"];
let functionBody = 'console.log("Hello, " + name + "!");';
let func = new Function('name', functionBody);
func.apply(null, functionArguments);
In the above example, we create a new function with the Function
constructor. The constructor takes a variable number of arguments. The last argument is the function body as a string, and the preceding arguments are the names of the arguments for the function.
After creating the function, we can call it using the apply()
method, passing the arguments as an array.
Wait! Using new Function
like this to call code from a string is dangerous. It opens up your application to all kinds of potential security issues. You should only use this method as a very last resort.
Executing Namespace Functions
Sometimes, functions are not global but are nested within objects or "namespaces". In such cases, we can still execute them by accessing the object properties.
Consider the following example:
let myNamespace = {
myFunction: function(name) {
console.log('Hello, ' + name + '!');
}
};
let functionName = "myFunction";
let functionArguments = ["John"];
myNamespace[functionName].apply(myNamespace, functionArguments);
In this example, myFunction
is a property of the myNamespace
object. We can access it using bracket notation and then call it with the apply()
method.
But what if the function name was specified in dot notation? To make this work, you'd need to split the object/function names by the periods and access each object before calling the function. This can be achieved with a function like this:
let myNamespace = {
functions: {
hello: function(name) {
console.log('Hello, ' + name + '!');
}
}
};
let functionName = "functions.hello";
let context = myNamespace;
let namespaces = functionName.split(".");
let func = namespaces.pop();
for (let i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func].apply(context, args);
Using this, we can execute functions of arbitrary namespace depth.
Security Considerations
While these methods can be quite useful, it's important to remember that executing code from a string can be a security risk. This is especially true when using the eval()
function or the Function
constructor, as they will execute any JavaScript code. If you're dealing with user input, this will lead to code injection attacks.
Note: Always validate and sanitize user input before using it in your code. Avoid executing code from strings whenever possible.
Conclusion
In this Byte, we've showed a few different methods of executing a JavaScript function when you have its name as a string. We've seen how to use the window
object, the Function
constructor, and even how to execute functions within namespaces. While these techniques can be useful, it's important to use them responsibly to avoid potential security risks.