前言

最近在项目重构代码时发现很多地方用到 eval() 这个函数,也不知是哪位大神写的神奇代码,于是乎就上网搜了一下关于 eval() 这个函数的用法,具体整理如下:

定义

eval() 函数执行表示为字符串形式的JavaScript代码。

语法

1
eval(string)

参数

string
一个字符串表示了一个JavaScript运算式,语句, 或者是一系列语句。运算式可以包括变量和已存在对象的属性。

返回值

执行指定的代码之后的完整值。如果完整值为空,返回undefined

说明

eval()是全局对象的一个函数属性。

eval()的参数是一个字符串。如果字符串表示了一个运算式,eval()会对运算式求值。如果参数表示了一个或多个JavaScript语句, 那么eval()会执行这些语句。不要调用eval()来执行一个四则运算运算式; JavaScript 会自动为四则运算求值。

1
2
eval(new String("2 + 2")); // 返回了包含"2 + 2"的字符串对象
eval("2 + 2"); // returns 4

该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。因此请不要为 eval() 函数传递 String 对象来作为参数。

不过可以使用 toString() 方法来绕过这个限制

1
2
var str = new String("2 + 2");
eval(str.toString()); // 4

如果试图覆盖 eval 属性或把 eval() 方法赋予另一个属性,并通过该属性调用它,则 ECMAScript 实现允许抛出一个 EvalError 异常。

避免在不必要的情况下使用eval

eval() 是一个危险的函数, 他执行的代码拥有着执行者的权利。如果你运行eval()伴随着字符串,那么你的代码可能被恶意方(不怀好意的人)影响, 通过在使用方的机器上使用恶意代码,可能让你失去在网页或者扩展程序上的权限。更重要的是,第三方代码可以看到作用域在某一个eval()被调用的时候,这有可能导致一些不同方式的攻击。相似的Function就是不容易被攻击的。

eval()也普遍的比其他的替代方案慢,因为他会调用js解析器,即便一些其他的构造器已经被做了优化在现代的JS引擎中。

更为安全(也更快)的替代eval()的是普通的用例。

JavaScript 为什么不推荐使用 eval()

  • eval只是一个普通的函数,只不过他有一个快速通道通向编译器,可以将string变成可执行的代码。有类似功能的还有Function , setInterval 和 setTimeout。
  • eval不容易调试。用chromeDev等调试工具无法打断点调试,所以麻烦的东西也是不推荐使用的。
  • 说到性能问题,在旧的浏览器中如果你使用了eval,性能会下降10倍。在现代浏览器中有两种编译模式:fast path和slow path。fast path是编译那些稳定和可预测(stable and predictable)的代码。而明显的,eval不可预测,所以将会使用slow path ,所以会慢。还有一个是,在使用类似于Closure Compiler等压缩(混淆)代码时,使用eval会报错。
  • 关于安全性,我们经常听到eval是魔鬼,他会引起XSS攻击,实际上,如果我们对信息源有足够的把握时,eval并不会引起很大的安全问题。而且不光是eval,其他方式也可能引起安全问题。
    比如:莫名其妙给你注入一个<script src="">标签,或者一段来历不明的JSON-P请求,再或者就是Ajax请求中的eval代码… 所以啊,只要你的信息源不安全,你的代码就不安全。不单单是因为eval引起的。你用eval的时候会在意XSS的问题,你越在意就越出问题,出的多了,eval就成噩梦了。
  • 效率问题是程序逻辑问题。对于一些有执行字符串代码需求的程序中,不用eval而用其他方式模拟反而会带来更大的开销

总结

因此,在实际项目中尽可能的避免使用 eval() ,除非特殊场景必须要使用。

ddAnswer

更多文章请关注微信公众号: zhiheng博客

ps:其实我是在扯淡,,,,