我正在编写一些JavaScript代码来解析用户输入的函数(用于类似电子表格的功能)。解析完公式后,我可以将其转换为JavaScript并在其上运行eval()以产生结果。

然而,我总是避免使用eval(),因为它是邪恶的(而且,无论正确与否,我一直认为它在JavaScript中更邪恶,因为要计算的代码可能会被用户更改)。

那么,什么时候可以使用它呢?


当前回答

我看到有人提倡不要使用eval,因为这是邪恶的,但我也看到同样的人动态地使用Function和setTimeout,所以他们在幕后使用eval:D

顺便说一句,如果你的沙盒不够确定(例如,如果你在一个允许代码注入的网站上工作),eval是你的最后一个问题。安全的基本规则是所有输入都是邪恶的,但对于JavaScript,甚至JavaScript本身也可能是邪恶的,因为在JavaScript中,你可以覆盖任何函数,你只是不能确定你使用的是真正的函数,所以,如果恶意代码在你之前启动,你不能相信任何JavaScript内置函数:D

现在这篇文章的尾声是:

如果你真的需要它(80%的时间不需要eval),并且你确定你在做什么,只使用eval(或更好的Function;)),闭包和OOP覆盖了80/90%的情况,其中eval可以使用另一种逻辑替换,其余是动态生成的代码(例如,如果你正在编写解释器),正如你已经说过的评估JSON(这里你可以使用Crockford安全评估;))

其他回答

Eval很少是正确的选择。虽然在许多情况下,您可以通过将脚本连接在一起并动态运行来完成需要完成的任务,但您通常可以使用更强大和可维护的技术:关联数组符号(obj["prop"]与obj.prop相同)、闭包、面向对象技术、函数技术—请使用它们。

当你相信消息来源时。

在JSON的情况下,它或多或少很难篡改源代码,因为它来自你控制的web服务器。只要JSON本身不包含用户上传的数据,使用eval就没有什么大的缺点。

在所有其他情况下,在将用户提供的数据提供给eval()之前,我将竭尽全力确保它符合我的规则。

什么时候JavaScript的eval()不是邪恶的?

我总是不鼓励使用eval。几乎总是有更干净和可维护的解决方案可用。Eval甚至对于JSON解析也不需要。Eval增加了维护的难度。道格拉斯·克罗克福德(Douglas Crockford)这样的大师并不赞同这一点,这不无道理。

但我发现了一个应该使用它的例子:

当你需要传递表达式时。

例如,我有一个函数,为我构造了一个通用的google.maps.ImageMapType对象,但我需要告诉它配方,它应该如何从缩放和坐标参数构造tile URL:

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

当没有宏时,Eval对于代码生成很有用。

举个愚蠢的例子,如果你正在编写一个Brainfuck编译器,你可能想要构造一个函数,它以字符串的形式执行指令序列,并对它进行eval以返回一个函数。

底线

如果你创建或净化了你评估的代码,它永远不会是邪恶的。

略为详细

如果在服务器上使用不是由开发人员创建或未经过开发人员处理的客户端提交的输入运行Eval是邪恶的。

如果在客户端上运行Eval,即使使用客户端制作的未经处理的输入,它也不是邪恶的。

显然,您应该始终清理输入,以便对代码使用的内容有一定的控制。

推理

客户端可以运行任何他们想要的代码,即使开发人员没有编写这些代码;这不仅适用于被求值的对象,而且适用于对eval本身的调用。