我正在编写一些JavaScript代码来解析用户输入的函数(用于类似电子表格的功能)。解析完公式后,我可以将其转换为JavaScript并在其上运行eval()以产生结果。
然而,我总是避免使用eval(),因为它是邪恶的(而且,无论正确与否,我一直认为它在JavaScript中更邪恶,因为要计算的代码可能会被用户更改)。
那么,什么时候可以使用它呢?
我正在编写一些JavaScript代码来解析用户输入的函数(用于类似电子表格的功能)。解析完公式后,我可以将其转换为JavaScript并在其上运行eval()以产生结果。
然而,我总是避免使用eval(),因为它是邪恶的(而且,无论正确与否,我一直认为它在JavaScript中更邪恶,因为要计算的代码可能会被用户更改)。
那么,什么时候可以使用它呢?
当前回答
由于还没有人提到它,让我补充一下eval对于Webassembly-Javascript互操作非常有用。虽然在您的页面中包含WASM代码可以直接调用的预先制作的脚本当然是理想的,但有时这是不可行的,您需要从Webassembly语言(如c#)传入动态Javascript来真正完成您需要做的事情。
在这种情况下,它也是安全的,因为您可以完全控制传入的内容。好吧,我应该说,这并不比使用c#编写SQL语句更安全,也就是说,无论何时使用用户提供的数据来生成脚本,都需要谨慎地执行(正确转义字符串等)。但在这种情况下,它在互操作场景中有一个明确的位置,远非“邪恶”。
其他回答
什么时候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也不是坏事。但是我偶然发现的99.9%的eval使用是不需要的(不包括setTimeout的东西)。
对我来说,邪恶不是性能问题,甚至不是安全问题(好吧,间接地,两者都是)。所有这些不必要的eval使用都增加了维护的难度。重构工具被抛弃了。搜索代码是困难的。这些评估的意想不到的影响是很多的。
当没有宏时,Eval对于代码生成很有用。
举个愚蠢的例子,如果你正在编写一个Brainfuck编译器,你可能想要构造一个函数,它以字符串的形式执行指令序列,并对它进行eval以返回一个函数。
让我们看看真正的人:
现在每个主流浏览器都有一个内置的控制台,你想成为黑客的人可以使用它来调用任何值的任何函数-为什么他们会麻烦使用eval语句-即使他们可以? 如果编译2000行JavaScript需要0.2秒,那么如果我计算4行JSON,性能会下降多少?
即使克罗克福德对“eval是邪恶的”的解释也很软弱。
eval是邪恶的,eval函数是最被滥用的功能 JavaScript。避免它
正如克罗克福德自己可能会说的那样:“这种说法往往会产生非理性的神经症。别买它。”
理解eval并知道它什么时候可能有用更重要。例如,eval是评估软件生成的服务器响应的明智工具。
顺便说一句:Prototype.js直接调用eval 5次(包括在evalJSON()和evalResponse()中)。jQuery在parseJSON中使用它(通过函数构造函数)。
在Chrome (v28.0.1500.72)中调试时,我发现如果变量没有在产生闭包的嵌套函数中使用,则它们不会绑定到闭包。我想,这是JavaScript引擎的优化。
但是:当eval()在导致闭包的函数中使用时,外部函数的所有变量都被绑定到闭包中,即使它们根本没有被使用。如果有人有时间测试内存泄漏是否会由此产生,请在下面给我留言。
下面是我的测试代码:
(function () {
var eval = function (arg) {
};
function evalTest() {
var used = "used";
var unused = "not used";
(function () {
used.toString(); // Variable "unused" is visible in debugger
eval("1");
})();
}
evalTest();
})();
(function () {
var eval = function (arg) {
};
function evalTest() {
var used = "used";
var unused = "not used";
(function () {
used.toString(); // Variable "unused" is NOT visible in debugger
var noval = eval;
noval("1");
})();
}
evalTest();
})();
(function () {
var noval = function (arg) {
};
function evalTest() {
var used = "used";
var unused = "not used";
(function () {
used.toString(); // Variable "unused" is NOT visible in debugger
noval("1");
})();
}
evalTest();
})();
我想在这里指出的是,eval()不一定指向本机eval()函数。这完全取决于函数的名称。因此,当使用别名调用本机eval()时(说var noval = eval;然后在内部函数noval(expression);)中,当表达式引用了应该是闭包的一部分但实际上不是的变量时,表达式的求值可能会失败。