有没有办法用javascript从字符串创建函数?


107

例如;

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

var fnc = aMethod(s);

如果这是字符串,则需要一个名为fnc的函数。并fnc();弹出警报屏幕。

eval("alert(1);") 不能解决我的问题。

Answers:


73

我添加了jsperf测试,以4种不同的方式从string创建函数:

  • 将RegExp与Function类一起使用

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

  • 将Function类与“ return”一起使用

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

  • 使用官方的Function构造函数

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

  • 使用评估

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

http://jsben.ch/D2xTG

2个结果样本: 在此处输入图片说明 在此处输入图片说明


@KthProg放松下来;)。并非总是很糟糕,在这种情况下,jsperf目前处于关闭状态,幸运的是,当我收到Bulk的评论时,我在关闭之前添加了结果屏幕截图。
phnah '16

@KthProg仅供参考,这是审核系统生成的罐头响应:)它在队列中弹出,我们检查预定的问题,此注释旨在解决其中的一个问题。这不是一成不变的规则,您会注意到注释是以建议而不是命令的形式出现的。
丹·史密斯,

174

从字符串创建函数的更好方法是使用Function

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

这具有优点/缺点,即当前范围内的变量(如果不是全局变量)不适用于新构造的函数。

也可以传递参数:

var addition = Function("a", "b", "return a + b;");
alert(addition(5, 3)); // shows '8'

5
同意,Function您不会污染本地范围,这就是为什么eval使引擎难以优化的原因...对于OP示例,我将:var fnc = Function('return '+s)();
CMS

我认为这可能是公认的答案。它比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 2011年

4
eval对未来的搜索者的强制性警告:eval可能会为黑客带来漏洞:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference / ...但是,如果您知道它的危险并且可以避免它们,那么这是一种很好的简单方法从字符串创建函数

如果您没有函数名,因为它来自数据库记录,该怎么办?
Marcel Djaman

13

是的,using 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


您好,请支持箭头功能支持此方法吗?
sathish kumar,

1
我在typecirpt中收到此错误“类型'String'上不存在属性'parseFunction'。”
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]))

谢谢。非常有趣
ДмитрийВасильев
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.