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

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

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


当前回答

唯一需要使用eval()的情况是需要动态地运行JS。我说的是你从服务器异步下载的JS…

...10次中的9次你都可以通过重构来避免这种情况。

其他回答

当你相信消息来源时。

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

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

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

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

现在这篇文章的尾声是:

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

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

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

我的使用eval: import的例子。

通常的做法。

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

但是在eval和一个小helper函数的帮助下,它得到了更好的外观:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

Importable可能看起来像这样(此版本不支持导入具体成员)。

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

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