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

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

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


当前回答

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

其他回答

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

我想花点时间谈谈你的问题的前提——eval()是“邪恶的”。“邪恶”这个词,在编程语言的使用者中,通常意味着“危险”,或者更准确地说,“能够用一个看起来简单的命令造成很多伤害”。那么,什么时候可以使用危险的东西呢?当你知道危险是什么,并采取适当的预防措施时。

首先,让我们看看使用eval()的危险。就像其他事情一样,可能有许多小的隐患,但是两个大的风险——eval()被认为是邪恶的原因——是性能和代码注入。

Performance - eval() runs the interpreter/compiler. If your code is compiled, then this is a big hit, because you need to call a possibly-heavy compiler in the middle of run-time. However, JavaScript is still mostly an interpreted language, which means that calling eval() is not a big performance hit in the general case (but see my specific remarks below). Code injection - eval() potentially runs a string of code under elevated privileges. For example, a program running as administrator/root would never want to eval() user input, because that input could potentially be "rm -rf /etc/important-file" or worse. Again, JavaScript in a browser doesn't have that problem, because the program is running in the user's own account anyway. Server-side JavaScript could have that problem.

说到你的具体情况。根据我的理解,您自己生成字符串,所以假设您小心地不允许生成像“rm -rf something-important”这样的字符串,就没有代码注入风险(但请记住,在一般情况下很难确保这一点)。此外,如果你在浏览器中运行,那么我相信代码注入的风险是相当小的。

至于性能,您必须将其与编码的便捷性进行权衡。我的观点是,如果要解析公式,不妨在解析期间计算结果,而不是运行另一个解析器(eval()内的解析器)。但是使用eval()编码可能更容易,而且性能上的影响可能不太明显。在这种情况下,看起来eval()并不比任何其他可能为您节省时间的函数更邪恶。

我倾向于遵循Crockford关于eval()的建议,并完全避免使用它。即使是看起来需要它的方法也不需要。例如,setTimeout()允许您传递一个函数而不是eval。

setTimeout(function() {
  alert('hi');
}, 1000);

即使它是一个可信的源,我也不会使用它,因为JSON返回的代码可能是乱码,最好的情况下可能会产生一些不稳定的东西,最坏的情况下可能会暴露一些不好的东西。

Eval并不邪恶,只是被滥用了。

如果您创建了代码,或者可以信任它,那就没问题。 人们一直在说用户输入对eval不重要。嗯,有点~

如果用户输入到服务器,然后返回到客户端,那么这些代码就被用于eval而没有被净化。恭喜你,你打开了潘多拉的盒子,用户数据可以发送给任何人。

根据eval的位置不同,许多网站都使用spa, eval可以让用户更容易地访问应用程序内部,否则就不容易。现在他们可以做一个虚假的浏览器扩展,可以磁带到评估,并再次窃取数据。

我只是想知道你用评估有什么用。当您可以简单地创建方法来做这类事情,使用对象或类似的事情时,生成代码并不理想。

这是一个很好的使用eval的例子。 您的服务器正在读取您创建的swagger文件。许多URL参数是以{myParam}格式创建的。因此,您希望读取url,然后将它们转换为模板字符串,而不必进行复杂的替换,因为您有许多端点。你可以这样做。 注意,这是一个非常简单的例子。

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

代码生成。我最近写了一个叫做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()的性能在这种情况下也不是问题,因为您只需要解释一次生成的字符串,然后多次重用可执行输出。

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