Explain Codes LogoExplain Codes Logo

How to execute a JavaScript function when I have its name as a string

javascript
dynamic-execution
function-execution
javascript-advanced
Alex KataevbyAlex Kataev·Dec 22, 2024
TLDR

Leverage the bracket notation and global context object (window for browsers, global for Node.js) to execute a JavaScript function from a string name:

const functionName = 'echo'; window[functionName]?.();

Note, the optional chaining operator (?.) provides safety (it calls echo only if it's a function). For security, steer clear of eval.

When dealing with non-global contexts, use the Function constructor:

const functionName = 'sqrt'; const context = {}; // Your context object const func = new Function('return this.' + functionName).bind(context); typeof func() === 'function' && func();

Remember to populate context with your function for a successful execution within your intended scope.

Diving deeper into dynamic execution

The fast answer covers most use cases, but the rabbit hole goes much deeper. Let's traverse it, exploring advanced scenarios and optimal practices for invoking JS functions from string names.

Namespace navigation

When handling namespaced functions, consider this pattern:

const namespace = 'Lib.Math'; const functionName = 'calculateSquare'; const args = [9]; const context = window; // Modify if not the global context const namespaces = namespace.split('.'); // Splitting string const func = namespaces.reduce((ctx, ns) => ctx[ns], context)[functionName]; if (typeof func === 'function') { func.apply(context, args); // Bringing context and arguments together }

ES6 computed magic

For computed property names in ES6 to avoid magic strings when dealing with dynamically named functions within an object:

const obj = { [dynamicName]: function(arg) { // Function code here } }; const dynamicName = 'rollDice'; // Not sure if call or summon Voldemort! obj[dynamicName]?.(arg);

Frozen function hash

Maintain the integrity of your functions in a hash object using Object.freeze. Elsa from Frozen would be proud:

const perform = Object.freeze({ dance: (style) => `Doing the ${style} dance`, wink: (eye) => `Winking with the ${eye} eye` }); // Get groove on, darn it! const functionName = 'dance'; perform[functionName]?.('moonwalk');

A controlled yet dynamic approach

Taking a more controlled approach, we can also write a helper function:

function executeFunctionByName(functionName, context = window, args = []) { const func = functionName.split('.').reduce((ctx, name) => ctx[name], context); // Just making sure function isn't leading us on if (typeof func === 'function') { return func.apply(context, args); // Applying smooth context } } // Apply named function gravy! executeFunctionByName('App.Graphics.draw', undefined, ['circle']);

Securing your code

Always maintain the highest security standards to eliminate any potential injection attacks and prevent bugs wearing sunglasses!

Emphasizing on context

Ensuring that the context is correct is crucial when using dynamically allocated functions.

const remote = { favoriteShow: "Bargain Hunt", watchShow: function() { console.log(`Keep your eyes on ${this.favoriteShow}`); } }; const func = remote.watchShow; func.call(remote); // You guessed it!

Always ensure that the context is preserved to avoid the regular not what I meant to do programming scenario.

Against the 'eval' dark forces

While eval and Function() seem like great options for executing dynamic code, they can be security landmines, leading to XSS attacks. Approach with caution, like a snake pit or pineapple pizza.

Proxies to the rescue

For capturing function calls dynamically, ES6 Proxies act as a security camera:

const func = new Proxy({}, { get(target, propName) { if (typeof target[propName] === 'undefined') { return function(...args) { // Printing actual implementation console.log(`Invoked function "${propName}" with arguments:`, args); }; } return target[propName]; } }); // Secret service function call func.secretAgent('James Bond', '007');