这篇翻译不完整。请帮忙从英语翻译这篇文章

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

语法

eval(string)

参数

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

返回值

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

描述

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

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

这里的四则运算是指数学上的运算,如:3 + 4 * 4 / 6。注意这里面并没有变量,只是纯的数学运算,这样的运算式并不需要来调用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

你可以使用通用的的方法来绕过这个限制,如使用toString()

var expression = new String("2 + 2");
eval(expression.toString());

如果你间接的使用 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引擎中。

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

访问成员属性

你不应该去使用eval()来转换属性名字到属性。考虑下面的这个例子,这里的需要访问的对象的属性是未知的,知道代码被执行。这里可以被处理用exal:

var obj = { a: 20, b: 30 };
var propName = getPropName();

eval( 'var result = obj.' + propsName )

但是,eval()在这里不是必须的。事实上,他使用在这里是被阻止的。替代的是,使用属性访问器,它更快更安全:

var obj = { a: 20, b: 30 }
var propName = getPropName();
var result = obj[ propName ];

你还可以使用这个方法去访问子代的属性。使用eval()这里应该是这样:

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath(); // 返回  例如:"a.b.c"

eval( 'var result = obj.' + propPath )

避免eval()这里应该是通过分割属性地址然后循环进入不同的属性:

function getDescendantantProp(obj, desc) {
    var arr = desc.split('.');
    while(arr.length) {
        obj = obj[arr.shift()];
    }
    return obj;
}

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath(); // 返回,例如 "a.b.c"
var result = getDescendantProp(obj, propPath);

解析 JSON

在扩展中下载JSON和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]);

Cross-implementation compatibility

应该被注意的是,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);

See also

文档标签和贡献者

标签: 
 此页面的贡献者: Jiang-Xuan, Hugh, Binly42, ziyunfei, fscholz, qianjiahao, teoli, huguowei, Mgjbot, Laser
 最后编辑者: Jiang-Xuan,