Есть ли способ создать функцию из строки с помощью javascript?

108

Например;

var s = "function test(){
  alert(1);
}";

var fnc = aMethod(s);

Если это строка, мне нужна функция с именем fnc. И fnc();всплывает экран предупреждения.

eval("alert(1);") не решает мою проблему.

Ymutlu
источник

Ответы:

73

Я добавил тест jsperf для 4 разных способов создания функции из строки:

  • Использование RegExp с классом функции

    var func = "function (a, b) { return a + b; }".parseFunction();

  • Использование класса функции с "возвратом"

    var func = new Function("return " + "function (a, b) { return a + b; }")();

  • Использование официального конструктора функций

    var func = new Function("a", "b", "return a + b;");

  • Использование Eval

    eval("var func = function (a, b) { return a + b; };");

http://jsben.ch/D2xTG

2 образца результатов: введите описание изображения здесь введите описание изображения здесь

фна
источник
@KthProg Остынь;). Это не всегда плохо, как в этой ситуации, jsperf в данный момент не работает, к счастью, я добавил скриншоты результатов до его отключения, когда я получил комментарий от Bulk.
phnah
@KthProg К вашему сведению, это был шаблонный ответ, созданный системой модерации :) он появляется в очереди, и мы проверяем наличие заранее определенных проблем, одну из которых этот комментарий призван исправить. Это не жесткое правило, и вы заметите, что комментарий представлен в форме предложения, а не команды.
Дэн Смит
175

Лучший способ создать функцию из строки - использовать Function:

var fn = Function("alert('hello there')");
fn();

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

Также возможна передача аргументов:

var addition = Function("a", "b", "return a + b;");
alert(addition(5, 3)); // shows '8'
Lekensteyn
источник
5
Согласитесь, Functionвы не загрязняете локальную область видимости, и поэтому evalоптимизация движков настолько усложняется ... В примере с OP я бы var fnc = Function('return '+s)();
сказал
Я думаю, что это, вероятно, должен быть принятый ответ. Это намного безопаснее, чем eval ().
Брайан Рейнер,
Вы, мой друг, заслуживаете множества положительных отзывов. Это дает преимущество в создании функционального объекта, который может быть назначен событиям и т. Д. Например: element.onclick = Function ("alert ('test');");
Райан Григгс,
1
@RyanGriggs В вашем случае функциональность eval вам не нужна, поэтому ее лучше писать как element.onclick = function() { alert("test"); }.
Lekensteyn
1
Вы правы на моем примере. Однако, если вы хотите назначить произвольные функции, хранящиеся в строках, ваш метод идеален. Это то, что я на самом деле пытаюсь сделать. У меня есть несколько функций, хранящихся в строковых переменных, и я хочу назначить одну для действия onclick.
Райан Григгс
38

Вы довольно близки.

//Create string representation of function
var s = "function test(){  alert(1); }";

//"Register" the function
eval(s);

//Call the function
test();

Вот рабочая скрипка .

Джеймс Хилл
источник
Я знал, что функция объявлена, но не мог догадаться, как вызвать функцию. Большое спасибо.
ymutlu 04
4
Обязательное evalпредупреждение будущим поисковикам: evalможет открыть лазейки для хакеров: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ... но если вы знаете об опасностях и можете их избежать, тогда это хороший простой способ создать функцию из строки
что, если у вас нет имени функции, поскольку оно взято из записи базы данных?
Марсель Джаман
13

Да, использование Function- отличное решение, но мы можем пойти немного дальше и подготовить универсальный синтаксический анализатор, который анализирует строку и преобразовывает ее в настоящую функцию JavaScript ...

if (typeof String.prototype.parseFunction != 'function') {
    String.prototype.parseFunction = function () {
        var funcReg = /function *\(([^()]*)\)[ \n\t]*{(.*)}/gmi;
        var match = funcReg.exec(this.replace(/\n/g, ' '));

        if(match) {
            return new Function(match[1].split(','), match[2]);
        }

        return null;
    };
}

примеры использования:

var func = 'function (a, b) { return a + b; }'.parseFunction();
alert(func(3,4));

func = 'function (a, b) { alert("Hello from function initiated from string!"); }'.parseFunction();
func();

вот jsfiddle

Мистер Тыква
источник
привет, пожалуйста, поддержите поддержку функции стрелки для этого метода?
сатиш кумар
1
Я получаю эту ошибку в typescirpt «Свойство 'parseFunction' не существует для типа 'String'».
Cegone
11

Имена динамических функций в JavaScript

С помощью Function

var name = "foo";
// Implement it
var func = new Function("return function " + name + "(){ alert('hi there!'); };")();
// Test it
func();
// Next is TRUE
func.name === 'foo'

Источник: http://marcosc.com/2012/03/dynamic-function-names-in-javascript/

С помощью eval

var name = "foo";
// Implement it
eval("function " + name + "() { alert('Foo'); };");
// Test it
foo();
// Next is TRUE
foo.name === 'foo'

С помощью sjsClass

https://github.com/reduardo7/sjsClass

пример

Class.extend('newClassName', {
    __constructor: function() {
        // ...
    }
});

var x = new newClassName();
// Next is TRUE
newClassName.name === 'newClassName'
Эдуардо Куомо
источник
6

Этот метод может быть полностью эквивалентен методу eval, но я хотел добавить его, так как он может быть полезен для некоторых.

var newCode = document.createElement("script");

newCode.text = "function newFun( a, b ) { return a + b; }";

document.body.appendChild( newCode );

Функционально это похоже на добавление этого элемента <script> в конец вашего документа, например:

...

<script type="text/javascript">
function newFun( a, b ) { return a + b; }
</script>

</body>
</html>
Дэвид Ньюберри
источник
3

Используйте new Function()с возвратом внутри и выполняйте его немедленно.

var s = `function test(){
  alert(1);
}`;

var new_fn = new Function("return " + s)()
console.log(new_fn)
new_fn()

Фернандо Карвахаль
источник
1

Пример с динамическими аргументами:

let args = {a:1, b:2}
  , fnString = 'return a + b;';

let fn = Function.apply(Function, Object.keys(args).concat(fnString));

let result = fn.apply(fn, Object.keys(args).map(key=>args[key]))
Brunettdan
источник
Спасибо. Очень интересно
Дмитрий Васильев