有没有一种方法可以使用JavaScript从字符串中创建一个函数?

142
例如:
var s = "function test(){
  alert(1);
}";

var fnc = aMethod(s);

如果这是字符串,我想要一个名为 fnc 的函数。并且 fnc(); 会弹出警示框。

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

10个回答

204

使用 Function 是创建函数的更好方法:

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

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

也可以传递参数:

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

6
同意,使用Function可以避免污染本地作用域,这也是为什么eval对引擎的优化造成困难的原因...针对原帖的示例,我会这样做:var fnc = Function('return '+s)(); - Christian C. Salvadó
1
我认为这可能应该是被采纳的答案。它比eval()更安全。 - Bryan Rayner
你,我的朋友,值得许多赞。这样做的好处是可以创建一个函数对象,该对象可以分配给事件等。例如:element.onclick = Function("alert('test');"); - Ryan Griggs
1
@RyanGriggs 在你的情况下,你不需要“eval”功能,所以最好写成element.onclick = function() { alert("test"); } - Lekensteyn
1
你从我的例子中得出的结论是正确的。然而,如果你想要分配存储在字符串中的任意函数,你的方法是完美的。这正是我想做的事情。我有多个存储在字符串变量中的函数,并希望将其中一个分配给onclick操作。 - Ryan Griggs

117

我添加了一个 jsperf 测试,测试了四种不同的从字符串创建函数的方式:

  • 使用 Function 类和 RegExp

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

  • 使用带 "return" 的 Function 类

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

  • 使用官方 Function 构造器

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

  • 使用 Eval

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

http://jsben.ch/D2xTG

结果样例: 这里是图片描述 这里是图片描述


@KthProg 冷静点;)这并不总是坏事,就像这种情况一样,jsperf目前无法访问,幸运的是,在Bulk发表评论之前,我已经添加了结果截图。 - phnah
@KthProg FYI,这是由管理系统生成的预设回复 :) 它会在队列中弹出,我们会检查预先确定的问题之一,其中此评论旨在解决。这不是一个硬性规定,您会注意到该评论是以建议的形式而非命令的形式呈现的。 - Dan Smith
该链接重定向到动漫色情内容。 - Dunfield

40

你非常接近了。

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

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

//Call the function
test();

这里是一个有效的fiddle


我知道函数已经声明了,但是不知道该如何调用函数名。非常感谢。 - ymutlu
5
对于未来搜索者的强制性eval警告:eval可能会为黑客打开漏洞。但如果你知道它的危险并能避免它们,那么这是一种从字符串创建函数的不错而简单的方法。参考链接:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval - user993683
如果您没有函数名称,因为它来自数据库记录,该怎么办? - Marcel Djaman

16

是的,使用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
我在 TypeScript 中收到了以下错误信息: “类型 'String' 上不存在属性 'parseFunction'。” - Cegone

14

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'

使用eval 来源:http://marcosc.com/2012/03/dynamic-function-names-in-javascript/
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'

8

这种技术可能最终等同于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>

5

使用带有返回值的new Function(),并立即执行它。

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

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


2

一个带有动态参数的例子:

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

谢谢。非常有趣。 - Дмитрий Васильев

0
如果您有一个以字符串形式表示的函数表达式,并且想要将其变成一个函数,那么您需要在传递给new Function的字符串中包含一个返回语句。
const strFn = "const sum = (a, b) => a + b"

const newFn = new Function(`${strFn}; return sum`)();

console.log(newFn(2, 3)) // 5

如果您不想立即执行,可以使用 function.call 方法来执行。请记住它所接受的第一个参数是 this 值。

const newFn = new Function('const arrMultiplier = (arr) => arr.map(num => num * 2); return arrMultiplier')
console.log(newFn.call({}).call({}, [6, 4, 1, 0])); // [12, 8, 2, 0]

0
我只是创建了这个函数并使用了它。
var parseFunction = (stringFunction_)=>{    
    eval('var tempFunction = ' + stringFunction_);    
    return tempFunction;
}

然后可以从中获得功能
var func = parseFunction('(a,b) =>{return a + b;}');
func(2,2) 
//it will return 4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接