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

Двузначные правила для запоминания:

Если поля касаются, они рушатся. Вложенные элементы «прижимают», если только маржа отделяет их. Элементы вне «Потока» ведут себя по-разному. То есть, это поведение не применяется одинаково для плавающего или позиционного: фиксированное или положение: абсолютные элементы.

Брок Адамс прав, но я также хотел добавить, что «переполнение: hidden "также может предотвратить срыв вложенных полей.

961
задан Lightness Races in Orbit 29 June 2014 в 16:47
поделиться

9 ответов

Не используйте eval, если у вас абсолютно, положительно нет другого выбора.

Как уже упоминалось, использование чего-то подобного было бы лучшим способом сделать это:

window["functionName"](arguments);

Это, однако, не будет работать с функцией пространства имен:

window["My.Namespace.functionName"](arguments); // fail

Вот как вы это сделаете:

window["My"]["Namespace"]["functionName"](arguments); // succeeds

Чтобы упростить это и обеспечить некоторую гибкость, вот удобная функция:

function executeFunctionByName(functionName, context /*, args */) {
  var args = Array.prototype.slice.call(arguments, 2);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(context, args);
}

Вы бы назвали это вот так:

executeFunctionByName("My.Namespace.functionName", window, arguments);

Обратите внимание, вы можете передать в любом контексте, который вы хотите, так что это будет делать то же, что и выше:

executeFunctionByName("Namespace.functionName", My, arguments);
1345
ответ дан Liam 29 June 2014 в 16:47
поделиться

Я не могу не упомянуть еще один прием, который помогает, если у вас есть неизвестное количество аргументов, которые также передаются как часть строки , содержащей имя функции. Например:

var annoyingstring = 'call_my_func(123, true, "blah")';

Если ваш Javascript работает на HTML-странице, все, что вам нужно, это невидимая ссылка; Вы можете передать строку в атрибут onclick и вызвать метод click.

<a href="#" id="link_secret"><!-- invisible --></a>

$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();

Или создайте элемент <a> во время выполнения.

1
ответ дан Magnus Smith 29 June 2014 в 16:47
поделиться

Все ответы предполагают, что к функциям можно получить доступ через глобальную область видимости (также известное как окно). Тем не менее, ФП не сделал этого предположения.

Если функции находятся в локальной области видимости (или закрытии) и на них не ссылается какой-либо другой локальный объект, неудача: вам нужно использовать eval () AFAIK, см. , динамически вызывать local функция в JavaScript

15
ответ дан Community 29 June 2014 в 16:47
поделиться

Две вещи:

  • избегать Eval, это очень опасно и медленно

  • во-вторых, не имеет значения, где ваша функция существует, " глобальное "-несущество" не имеет значения. x.y.foo() можно активировать через x.y['foo'](), x['y']['foo']() или даже window['x']['y']['foo'](). Вы можете цепляться бесконечно, как это.

22
ответ дан annakata 29 June 2014 в 16:47
поделиться

С ES6 вы можете получить доступ к методам класса по имени:

class X {
  method1(){
    console.log("1");
  }
  method2(){
    this['method1']();
    console.log("2");
  }
}
let x  = new X();
x['method2']();

вывод будет:

1
2
25
ответ дан nils petersohn 29 June 2014 в 16:47
поделиться

Просто подумал, что выложу слегка измененную версию очень полезной функции Джейсона Бантинга .

Во-первых, я упростил первое утверждение, указав второй параметр для slice () . Оригинальная версия работала нормально во всех браузерах, кроме IE.

Во-вторых, я заменил этот на контекст в операторе возврата; в противном случае этот всегда указывал на окно , когда выполнялась целевая функция.

function executeFunctionByName(functionName, context /*, args */) {
    var args = Array.prototype.slice.call(arguments, 2);
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for (var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }
    return context[func].apply(context, args);
}
96
ответ дан Community 29 June 2014 в 16:47
поделиться

Итак, как и другие говорили, определенно лучший вариант:

window['myfunction'](arguments)

И, как сказал Джейсон Бантинг , он не будет работать, если имя вашей функции включает объект :

window['myobject.myfunction'](arguments); // won't work
window['myobject']['myfunction'](arguments); // will work

Итак, вот моя версия функции, которая будет выполнять все функции по имени (включая объект или нет):

my = {
    code : {
        is : {
            nice : function(a, b){ alert(a + "," + b); }
        }
    }
};

guy = function(){ alert('awesome'); }

function executeFunctionByName(str, args)
{
    var arr = str.split('.');
    var fn = window[ arr[0] ];
    
    for (var i = 1; i < arr.length; i++)
    { fn = fn[ arr[i] ]; }
    fn.apply(window, args);
}

executeFunctionByName('my.code.is.nice', ['arg1', 'arg2']);
executeFunctionByName('guy');
3
ответ дан Community 29 June 2014 в 16:47
поделиться

Ответ на этот другой вопрос показывает Вам, как сделать это: JavaScript, эквивалентный из Python' s местные жители ()?

В основном, можно сказать

window["foo"](arg1, arg2);

или как многие другие предположили, можно просто использовать оценку:

eval(fname)(arg1, arg2);

, хотя это чрезвычайно небезопасно, если Вы не абсолютно уверены в том, что Вы - луг оценки.

59
ответ дан Community 30 June 2014 в 03:47
поделиться

Люди продолжают говорить, что eval является опасным и злым, потому что это может выполнить любой произвольный код. Однако при использовании оценки с белый список подход, предполагая знание всех возможных имен функций, которые, возможно, должны быть выполнены заранее, затем оценка больше не является проблемой безопасности, потому что вход больше не произволен . Белый список является хорошим и частым шаблоном безопасности. Вот пример:

function runDynamicFn(fnName, ...args) {
  // can also be fed from a tightly controlled config
  const allowedFnNames = ['fn1', 'ns1.ns2.fn3', 'ns4.fn4'];

  return allowedFnNames.includes(fnName) ? eval(fnName)(...args) : undefined; 
}

// test function:
function fn1(a) { 
  console.log('fn1 called with', a)
}

runDynamicFn('alert("got you!")')
runDynamicFn('fn1', 'foo')
0
ответ дан 19 December 2019 в 20:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: