How to turn a String into a JavaScript function call? [duplicate]

How to turn a String into a JavaScript function call? [duplicate]

This question already has an answer here:

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

32 answers

I got a string like:
settings.functionName + ‘(‘ + t.parentNode.id + ‘)’;

that I want to translate into a function call like so:
clickedOnItem(IdofParent);

This of course will have to be done in JavaScript. When I do an alert on settings.functionName + ‘(‘ + t.parentNode.id + ‘)’; it seems to get everything correct. I just need to call the function that it would translate into.
Legend:
settings.functionName = clickedOnItem

t.parentNode.id = IdofParent

Solutions/Answers:

Solution 1:

Seeing as I hate eval, and I am not alone:

var fn = window[settings.functionName];
if(typeof fn === 'function') {
    fn(t.parentNode.id);
}

Edit: In reply to @Mahan’s comment:
In this particular case, settings.functionName would be "clickedOnItem". This would, at runtime translate var fn = window[settings.functionName]; into var fn = window["clickedOnItem"], which would obtain a reference to function clickedOnItem (nodeId) {}. Once we have a reference to a function inside a variable, we can call this function by “calling the variable”, i.e. fn(t.parentNode.id), which equals clickedOnItem(t.parentNode.id), which was what the OP wanted.

Related:  How to open generated pdf using jspdf in new window

More full example:

/* Somewhere: */
window.settings = {
  /* [..] Other settings */
  functionName: 'clickedOnItem'
  /* , [..] More settings */
};

/* Later */
function clickedOnItem (nodeId) {
  /* Some cool event handling code here */
}

/* Even later */
var fn = window[settings.functionName]; 
/* note that settings.functionName could also be written
   as window.settings.functionName. In this case, we use the fact that window
   is the implied scope of global variables. */
if(typeof fn === 'function') {
    fn(t.parentNode.id);
}

Solution 2:

window[settings.functionName](t.parentNode.id);

No need for an eval()

Solution 3:

Here is a more generic way to do the same, while supporting scopes :

// Get function from string, with or without scopes (by Nicolas Gauthier)
window.getFunctionFromString = function(string)
{
    var scope = window;
    var scopeSplit = string.split('.');
    for (i = 0; i < scopeSplit.length - 1; i++)
    {
        scope = scope[scopeSplit[i]];

        if (scope == undefined) return;
    }

    return scope[scopeSplit[scopeSplit.length - 1]];
}

Hope it can help some people out.

Solution 4:

JavaScript has an eval function that evaluates a string and executes it as code:

eval(settings.functionName + '(' + t.parentNode.id + ')');

Solution 5:

eval() is the function you need to do that, but I’d advise trying one of these things to minimize the use of eval. Hopefully one of them will make sense to you.

Related:  How can I get the index of an array in a Meteor template each loop?

Store the function

Store the function as a function, not as a string, and use it as a function later. Where you actually store the function is up to you.

var funcForLater = clickedOnItem;

// later is now
funcForLater(t.parentNode.id);

or

someObject.funcForLater = clickedOnItem;    
// later is now    
(someObject.funcForLater)(t.parentNode.id);

Store function name

Even if you have to store the function name as a string, you can minimize complexity by doing

(eval(settings.functionName))(t.parentNode.id);

which minimizes the amount of Javascript you have to construct and eval.

Dictionary of handlers

Put all of the action functions you might need into an object, and call them dictionary-style using the string.

// global
itemActions = { click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ };

// Later...
var actionName = "click"; // Or wherever you got the action name
var actionToDo = itemActions[actionName];
actionToDo(t.parentNode.id);

(Minor note: If instead here you used syntax itemActions[actionName](t.parentNode.id); then the function would be called as a method of itemActions.)

Solution 6:

While I like the first answer and I hate eval, I’d like to add that there’s another way (similar to eval) so if you can go around it and not use it, you better do. But in some cases you may want to call some javascript code before or after some ajax call and if you have this code in a custom attribute instead of ajax you could use this:

    var executeBefore = $(el).attr("data-execute-before-ajax");
    if (executeBefore != "") {
        var fn = new Function(executeBefore);
        fn();
    }

Or eventually store this in a function cache if you may need to call it multiple times.

Related:  Difference between screen.availHeight and window.height()

Again – don’t use eval or this method if you have another way to do that.