How to turn a String into a JavaScript function ca

2018-12-31 17:34发布

问题:

This question already has an answer here:

  • How to execute a JavaScript function when I have its name as a string 31 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

回答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.

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);
}


回答2:

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

No need for an eval()



回答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.



回答4:

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

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


回答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.

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.)



回答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.

Again - don\'t use eval or this method if you have another way to do that.



回答7:

If settings.functionName is already a function, you could do this:

settings.functionName(t.parentNode.id);

Otherwise this should also work if settings.functionName is just the name of the function:

if (typeof window[settings.functionName] == \"function\") {
    window[settings.functionName](t.parentNode.id);
}


回答8:

I wanted to be able to take a function name as a string, call it, AND pass an argument to the function. I couldn\'t get the selected answer for this question to do that, but this answer explained it exactly, and here is a short demo.

function test_function(argument)    {
    alert(\'This function \' + argument); 
}

functionName = \'test_function\';

window[functionName](\'works!\');

This also works with multiple arguments.



回答9:

This took me a while to figure out, as the conventional window[\'someFunctionName\']() did not work for me at first. The names of my functions were being pulled as an AJAX response from a database. Also, for whatever reason, my functions were declared outside of the scope of the window, so in order to fix this I had to rewrite the functions I was calling from

function someFunctionName() {}

to

window.someFunctionName = function() {}

and from there I could call window[\'someFunctionName\']() with ease. I hope this helps someone!



回答10:

Based on Nicolas Gauthier answer:

var strng = \'someobj.someCallback\';
var data = \'someData\';

var func = window;
var funcSplit = strng.split(\'.\');
for(i = 0;i < funcSplit.length;i++){
   //We maybe can check typeof and break the bucle if typeof != function
   func = func[funcSplit[i]];
}
func(data);


回答11:

I prefer to use something like this:

window.callbackClass[\'newFunctionName\'] = function(data) { console.log(data) };
...
window.callbackClass[\'newFunctionName\'](data);


回答12:

In javascript that uses the CommonJS spec, like node.js for instance you can do what I show below. Which is pretty handy for accessing a variable by a string even if its not defined on the window object. If there is a class named MyClass, defined within a CommonJS module named MyClass.js

// MyClass.js
var MyClass = function() {
    // I do stuff in here. Probably return an object
    return {
       foo: \"bar\"
    }
}

module.exports = MyClass;

You can then do this nice bit o witchcraft from another file called MyOtherFile.js

// MyOtherFile.js

var myString = \"MyClass\";

var MyClass = require(\'./\' + myString);
var obj = new MyClass();

console.log(obj.foo); // returns \"bar\"

One more reason why CommonJS is such a pleasure.



回答13:

eval(\"javascript code\");

it is extensively used when dealing with JSON.