eval()
函数会将传入的字符串当做JavaScript代码进行执行。
语法
eval(string)
返回值
执行指定代码之后的返回值。如果返回值为空,返回undefined
描述
eval()是全局对象的一个函数属性。
eval()
的参数是一个字符串。如果字符串表示的是表达式,eval()会对表达式进行求值。如果参数表示一个或多个JavaScript语句, 那么eval()就会执行这些语句。注意不要用eval()来执行一个四则运算表达式;因为 JavaScript 会自动为四则运算求值并不需要用eval来包裹。
如果要将算数表达式构造成为一个字符串,你可以用eval()在随后对其求值。比如,假如你有一个变量 x ,你可以通过一个字符串表达式来对涉及x的表达式延迟求值,将 "3 * x + 2
",存储为变量,然后在你的脚本后面的一个地方调用eval()。
如果eval()的参数不是字符串,
eval()将会将参数原封不动的返回。
在下面的例子中,字符串构造器被指定,eval()返回了字符串对象而不是对字符串求值。
eval(new String("2 + 2")); // 返回了包含"2 + 2"的字符串对象
eval("2 + 2"); // returns 4
如果你间接的使用
eval()
, 如通过一个引用来调用它而不是直接的调用eval。 从
ECMAScript 5
起它工作在全局作用域而不是局部作用域中;这就意味着,例如,下面的代码的作用声明创建一个全局函数,并且geval中的这些代码在执行期间不能在被调用的作用域中访问局部变量。
function test() {
var x = 2, y = 4;
console.log(eval("x + y")); // 直接调用,使用本地作用域,结果是 6
var geval = eval;
console.log(geval("x + y")); // 间接调用,使用全局作用域,throws ReferenceError 因为`x`未定义
}
避免在不必要的情况下使用eval
eval()
是一个危险的函数, 他执行的代码拥有着执行者的权利。如果你用eval()运行的字符串代码被恶意方(不怀好意的人)操控修改,您可能会利用最终在用户机器上运行恶意方部署的恶意代码,并导致您失去您的网页或者扩展程序的权限。更重要的是,第三方代码可以看到某一个eval()被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的Function就是不容易被攻击的。
eval()的运行效率也普遍的比其他的替代方案慢,因为他会调用js解析器,即便现代的JS引擎中已经对此做了优化。
在常见的案例中我们都回找更安全或者更快的方案去替换他
解析 JSON(将字符串转化为JavaScript对象)
如果你在调用eval()传入的字符串参数中更包含数据(如:一个数组“[1,2,3]”)而不是代码,你应该考虑将其转换为JSON对象,这允许你用JavaScript语法的子集来表示数据。在扩展中下载JSON和JavaScript
提示:因为JSON语法子集相对于JavaScript语法子集比较有局限性,很多在JavaScript中可用的特性在JSON中就不起作用了,如:后缀都好JSON就不支持,并且,对象中的属性名在JSON中必须用引号括起来,所以在使用JSON序列化将字符串转化为JSON对象时需确认字符串格式
在很多扩展中常见的用法是使用XMLHttpRequest(或者其他机制)从一个远程的网站下载 JavaScript 或者JSON(这两者是不同的!)一旦内容下载完成,扩展的作者就会使用 eval()
继续进行解码的工作,把字串内容转换成 JavaScript 对象。这样的做法是非常危险的,并且,实际上不会通过AMO的审核。所以这样的扩展将不会被允许离开AMO的砂箱。
这种做法是危险的是因为解码后的 JavaScript 具有全部的 chrom 权限并且可以执行一些很恶劣的动作.一个扩展下载下来的JavaScript如何能执行恶劣的动作?如果承载 JavaScript 的网络服务器被劫持了或者被攻陷了,那就很容易了。这种情况是有可能发生的。AMO很认真地看待这种危险。
好消息是我们有很多方法来绕开这个问题。
下载 JSON
如果扩展是需要下载JSON,那么开发人员应该使用在这里讨论过的某种JSON解码方法,而千万不要使用eval()
。JSON是有关状态的,并不允许解码函数。扩展开发人员可用的JSON解码方法保护了扩展免于受到恶意的JSON和JavaScrip的侵害。从远端的服务器通过JSON下载状态变得日益流行。使用JSON解码器,而不是eval()
!
下载 JavaScript
当然了,有时候也有扩展中下载并插入 JavaScript 代码模块的时候。发生这些事情主要是因为扩展试图保持它的部分代码是干净和动态的,而扩展的作者又不想为每次脚本的变化发布一个新版本。在这种场合下,我们应该使用 JavaScript 的砂箱来把下载下来的JavaScript代码和扩展的其它代码部分以及宿主的应用给隔离开。
砂箱是通过使用Components.utils.evalInSandbox()
实现的。JavaScript 代码会被和任何JavaScript需要交互的"安全"的对象一起添加到砂箱里。砂箱自己也不是完全没有危险,开发者应该仔细阅读砂箱的文档页面,以确保不可信的代码不会从砂箱中泄露出来。
转化成员属性
你不应该在属性里通过eval来转化属性。考虑下面的例子: getFieldName(n)
函数将指定的表单元素按字符串返回, 将表单的第三个元素赋值给了一个变量声明 field ,第二句声明使用eval()来展示表单元素的值。
var field = getFieldName(3);
document.write("The field named ", field, " has value of ",
eval(field + ".value"));
也许,这里的eval()不是必要的,事实上,这里使用eval()是不鼓励的。 取而代之的是使用 member operators, 那会快很多:
var field = getFieldName(3);
document.write("The field named ", field, " has value of ",
field[value]);
浏览器交叉应用时的兼容处理
应该被注意的是,eval的第二个参数是非标准的,在JavaScript实现中不被支持的;在写这篇文章的时候,Rhino没有提供支持,也不是 Safari's 的核心JavaScript代码。
为了维持兼容性,采用交叉实现,它被推荐第二个参数不被使用,为了达到相同的效果,不如使用 with 声明 。
eval(string,object);
使用
with (object) {
eval(string);
}
例子
下面的例子展示了使用 document.write来输出。
在服务器端的 JavaScript,你可以使用write 函数来达到document.write的效果。
举例: 使用 eval
在下面的代码中,两种声明都返回了42。第一种是对字符串 "x + y + 1
"求值;第二种是对字符串 "42
"求值。
var x = 2;
var y = 39;
var z = "42";
eval("x + y + 1"); // returns 42
eval(z); // returns 42
举例: 使用 eval
对JavaScript声明求值
下面的例子使用eval()
对str字符串求值。这个字符串包含了JavaScript声明,如果x等于5,就打开一个Alert 对话框,然后对 z 赋值。 否则就对z赋值0。 当第二个声明被执行, eval 将会将str表达式执行,然后会对声明集合求值,并将返回值赋值给z。
var str = "if (x == 5) {alert('z is 42'); z = 42;} else z = 0; ";
document.write("<P>z is ", eval(str));
返回值
eval
将会返回对最后一个表达式的求值结果。
var str = "if ( a ) { 1+1; } else { 1+2; }";
var a = true;
var b = eval(str); // returns 2
alert("b is : " + b);
a = false;
b = eval(str); // returns 3
alert("b is : " + b);
学习笔记:地址https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval