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

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

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


当前回答

当您使用解析函数解析JSON结构时(例如,jQuery.parseJSON),它期望JSON文件的完美结构(每个属性名都用双引号括起来)。然而,JavaScript更加灵活。因此,可以使用eval()来避免它。

其他回答

Eval()并不坏。或者,如果是的话,它是邪恶的,就像反射、文件/网络I/O、线程和IPC在其他语言中的“邪恶”一样。

如果,出于您的目的,eval()比手动解释更快,或者使您的代码更简单,或更清楚……那么你应该使用它。如果两者都不是,那么你就不应该这么做。就这么简单。

代码生成。我最近写了一个叫做Hyperbars的库,它在虚拟世界和把手之间架起了桥梁。它通过解析句柄模板并将其转换为超脚本来实现这一点。超脚本首先作为字符串生成,在返回它之前,eval()将其转换为可执行代码。我发现eval()在这种特殊情况下与邪恶完全相反。

基本上从

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

这个

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

eval()的性能在这种情况下也不是问题,因为您只需要解释一次生成的字符串,然后多次重用可执行输出。

如果您好奇的话,您可以看到代码生成是如何实现的。

只要可以确定代码的源代码来自您或实际用户,就没有理由不使用eval()。尽管他可以操纵发送到eval()函数的内容,但这并不是一个安全问题,因为他能够操纵网站的源代码,因此可以改变JavaScript代码本身。

所以…何时不使用eval()?Eval()只应该在第三方有可能更改它的情况下才使用。比如拦截客户端和服务器之间的连接(但如果这是一个问题,请使用HTTPS)。你不应该用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对于Webassembly-Javascript互操作非常有用。虽然在您的页面中包含WASM代码可以直接调用的预先制作的脚本当然是理想的,但有时这是不可行的,您需要从Webassembly语言(如c#)传入动态Javascript来真正完成您需要做的事情。

在这种情况下,它也是安全的,因为您可以完全控制传入的内容。好吧,我应该说,这并不比使用c#编写SQL语句更安全,也就是说,无论何时使用用户提供的数据来生成脚本,都需要谨慎地执行(正确转义字符串等)。但在这种情况下,它在互操作场景中有一个明确的位置,远非“邪恶”。