最近项目中, 一个为了确保安全性而做的任务是移除代码中的eval
. 我对eval
的不好略有耳闻, 但是它到底有多不好? 今天了解下.
Douglas Crockford说过:
The eval function (and its relatives, Function, setTimeout, and setInterval) provide access to the JavaScript compiler. This is sometimes necessary, but in most cases it indicates the presence of extremely bad coding. The eval function is the most misused feature of JavaScript.
这句话被很多人用来佐证eval
的不好. eval
被认为为攻击者进行Cross-Site Scripting (XSS) 攻击创造了便利. 但其实使用得当, eval
并没有什么问题.
错误应用
比方说下面这段代码, 利用eval
去判断一个表单元素是否被选中.
function isChecked(optionNumber) {
return eval("forms[0].option" + optionNumber + ".checked");
}
var result = isChecked(1);
这段代码很容易用没有eval
的方式实现.
function isChecked(optionNumber) {
return forms[0]["option" + optionNumber].checked;
}
var result = isChecked(1);
这类似错误的eval
应用可以简单地使用[]
来避免.
调试
eval
中的代码为调试带来了难度. 现在Chrome Dev Tool可以debugeval
中的代码, 但是仍然很麻烦. 所以, 从这点出发, 为了开发效率, 也尽量不要用eval
.
效率
旧的浏览器中, 如果你使用eval
, 浏览器就要进行两次解析. 第一次解析JS代码本身, 第二次解析eval中的代码. 在不带JS编译引擎的浏览器中, 效率可能相差十倍.
即使对于带JS编译引擎的浏览器, eval
还是有问题. 大多数引擎运行代码时会在两种模式中选择: 一个是fast path, 一个是slow path. 如果代码稳定, 比较容易预测, 那么引擎会使用fast path运行代码, 效率高很多. 如果代码很难预测, 那只能用slow path运行了. 由于带eval
的代码本身很难预测, 所以会走slow path, 因此也会造成效率低下.
安全性
eval
最让人头疼的地方就是安全性了. 如果你将用户的输入作为eval
的参数, 那么就有XSS的风险. 但是你只要确保不做出这种事, 使用eval
也是没什么问题的.
另外一点是, 有些人说, 如果你使用eval
去运行浏览器返回的代码, 那么就有可能受到中间人攻击 (man-in-the-middle attack). 但是事实上, 如果一个人真的做到了中间人攻击, 除了用eval
, 有更多简单的方法让他运行恶意代码, 比如:
- 在代码中插入
<script src="">
并引用恶意代码. - 在JSON-P或者Ajax请求中插入恶意代码.
另外, 中间人攻击可以获取用户的cookie或者其他信息, 同时不篡改任何信息, 不被察觉. 这本身也是安全隐患, 与eval
无关.
总之, 如果你无法相信浏览器返回的代码, 那这本身产生的问题就远比eval
的问题大得多.
总结
eval
在调试和效率有不好的影响, 有一定的安全性隐患, 但是只要注意就可以避免. 总体来说, eval
尽量不要用.