Как превратить String в вызов функции JavaScript?

Я получил строку вроде:

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

что я хочу перевести на вызов функции следующим образом:

clickedOnItem(IdofParent);

Это, конечно, нужно сделать в JavaScript. Когда я делаю предупреждение на settings.functionName + '(' + t.parentNode.id + ')';, похоже, все правильно. Мне просто нужно вызвать функцию, в которую она будет переведена.

Условные обозначения:

settings.functionName = clickedOnItem

t.parentNode.id = IdofParent

Ответ 1

Видя, как я ненавижу eval, и я не один:

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

Изменить: В ответ на комментарий @Mahan: В этом конкретном случае settings.functionName будет "clickedOnItem". Это означает, что во время выполнения переведите var fn = window[settings.functionName]; в var fn = window["clickedOnItem"], что даст ссылку на function clickedOnItem (nodeId) {}. Как только у нас есть ссылка на функцию внутри переменной, мы можем вызвать эту функцию "вызовом переменной", т.е. fn(t.parentNode.id), которая равна clickedOnItem(t.parentNode.id), что и требовалось OP.

Более полный пример:

/* 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);

Нет необходимости в eval()

Ответ 3

Вот более общий способ сделать то же самое, поддерживая области:

// 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]];
}

Надеюсь, это поможет некоторым людям.

Ответ 4

JavaScript имеет функцию eval, которая оценивает строку и выполняет ее как код:

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

Ответ 5

eval() - это функция, которую вам нужно сделать, но я бы посоветовал попробовать одну из этих вещей, чтобы свести к минимуму использование eval. Надеюсь, один из них будет иметь для вас смысл.

Сохранить функцию

Храните функцию как функцию, а не как строку, и используйте ее как функцию позже. Где вы действительно храните функцию, зависит от вас.

var funcForLater = clickedOnItem;

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

или

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

Имя функции сохранения

Даже если вам нужно сохранить имя функции в виде строки, вы можете свести к минимуму сложность, выполнив

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

который минимизирует количество Javascript, которое вы должны построить, и eval.

Словарь обработчиков

Поместите все функции действий, которые могут вам понадобиться, в объект и вызовите их в словаре-стиле с помощью строки.

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

(Незначительное примечание: если вместо этого вы использовали синтаксис itemActions[actionName](t.parentNode.id);, тогда функция будет вызываться как метод itemActions.)

Ответ 6

В то время как мне нравится первый ответ, и я ненавижу eval, я хотел бы добавить, что есть другой способ (похожий на eval), поэтому, если вы можете обойти его и не использовать, вам лучше. Но в некоторых случаях вам может потребоваться вызвать код javascript до или после некоторого вызова ajax, и если у вас есть этот код в пользовательском атрибуте вместо ajax, вы можете использовать это:

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

Или, в конце концов, сохраните это в кеше функции, если вам может потребоваться позвонить ему несколько раз.

Опять же - не используйте eval или этот метод, если у вас есть другой способ сделать это.

Ответ 7

Если settings.functionName уже является функцией, вы можете сделать это:

settings.functionName(t.parentNode.id);

В противном случае это также должно работать, если settings.functionName - это просто имя функции:

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

Ответ 8

Я хотел иметь возможность взять имя функции в виде строки, вызвать ее и передать аргумент функции. Я не мог получить выбранный ответ для этого вопроса, но этот ответ объяснил это точно, и вот короткая демонстрация.

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

functionName = 'test_function';

window[functionName]('works!');

Это также работает с несколькими аргументами.

Ответ 9

Мне потребовалось некоторое время, чтобы понять, поскольку обычный window['someFunctionName']() не работал у меня сначала. Имена моих функций вытягивались как ответ AJAX из базы данных. Кроме того, по какой-то причине мои функции были объявлены вне области действия окна, поэтому, чтобы исправить это, мне пришлось переписать функции, которые я вызывал из

function someFunctionName() {}

к

window.someFunctionName = function() {}

и оттуда я мог бы легко вызвать window['someFunctionName'](). Надеюсь, это поможет кому-то!

Ответ 10

На основании ответа Николаса Готье:

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

Я предпочитаю использовать что-то вроде этого:

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

Ответ 12

В javascript, который использует спецификацию CommonJS, например node.js, вы можете сделать то, что я покажу ниже. Это довольно удобно для доступа к переменной с помощью строки, даже если она не определена в объекте window. Если существует класс с именем MyClass, определенный в модуле CommonJS с именем MyClass.js

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

module.exports = MyClass;

Затем вы можете сделать этот хороший бит о колдовстве из другого файла MyOtherFile.js

// MyOtherFile.js

var myString = "MyClass";

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

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

Еще одна причина, по которой CommonJS - такое удовольствие.

Ответ 13

eval("javascript code");

он широко используется при работе с JSON.