首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

eval

eval()函数会将传入的字符串当做JavaScript代码进行执行。

语法

代码语言:javascript
复制
eval(string)

参数

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

返回值

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

描述

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

eval()的参数是一个字符串。如果字符串表示的是表达式,eval()会对表达式进行求值。如果参数表示一个或多个JavaScript语句, 那么eval()就会执行这些语句。注意不要用eval()来执行一个四则运算表达式;因为 JavaScript 会自动为四则运算求值并不需要用eval来包裹。

如果要将算数表达式构造成为一个字符串,你可以用eval()在随后对其求值。比如,假如你有一个变量 x ,你可以通过一个字符串表达式来对涉及x的表达式延迟求值,将 "3 * x + 2",存储为变量,然后在你的脚本后面的一个地方调用eval()。

如果eval()的参数不是字符串,eval()将会将参数原封不动的返回。在下面的例子中,字符串构造器被指定,eval()返回了字符串对象而不是对字符串求值。

代码语言:javascript
复制
eval(new String('2 + 2')); // returns a String object containing "2 + 2"
eval('2 + 2');             // returns 4

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

代码语言:javascript
复制
var expression = new String('2 + 2');
eval(expression.toString());

如果你间接的使用 eval(), 如通过一个引用来调用它而不是直接的调用eval。 从ECMAScript 5起它工作在全局作用域而不是局部作用域中;这就意味着,例如,下面的代码的作用声明创建一个全局函数,并且geval中的这些代码在执行期间不能在被调用的作用域中访问局部变量。

代码语言:javascript
复制
function test() {
  var x = 2, y = 4;
  console.log(eval('x + y'));  // Direct call, uses local scope, result is 6
  var geval = eval; // equivalent to calling eval in the global scope
  console.log(geval('x + y')); // Indirect call, uses global scope, throws ReferenceError because `x` is undefined
  (0, eval)('x + y'); // another example of Indirect call
}

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

eval() 是一个危险的函数, 他执行的代码拥有着执行者的权利。如果你用eval()运行的字符串代码被恶意方(不怀好意的人)操控修改,您可能会利用最终在用户机器上运行恶意方部署的恶意代码,并导致您失去您的网页或者扩展程序的权限。更重要的是,第三方代码可以看到某一个eval()被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的Function就是不容易被攻击的。

eval()的运行效率也普遍的比其他的替代方案慢,因为他会调用js解析器,即便现代的JS引擎中已经对此做了优化。

在常见的案例中我们都会找更安全或者更快的方案去替换他

访问成员属性

你不应该去使用eval()来将属性名字转化为对象的属性属性。考虑下面的这个例子,被访问对象的属性在它被执行之前都会未知的。这里虽然可以被处理用eval:

代码语言:javascript
复制
var obj = { a: 20, b: 30 };
var propName = getPropName();  // returns "a" or "b"

eval( 'var result = obj.' + propName );

但是,这里并不是必须得使用eval()。事实上,这里并不支持这样使用。可以使用属性访问器进行代替,它更快而且更安全:

代码语言:javascript
复制
var obj = { a: 20, b: 30 };
var propName = getPropName();  // returns "a" or "b"
var result = obj[ propName ];  //  obj[ "a" ] is the same as obj.a

你还可以使用这个方法去访问子代的属性。如下:

代码语言:javascript
复制
var obj = {a: {b: {c: 0}}};
var propPath = getPropPath();  // returns e.g. "a.b.c"

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

这里则通过规避使用Eval()实现了循环获取子代的属性:

代码语言:javascript
复制
function getDescendantProp(obj, desc) {
  var arr = desc.split('.');
  while (arr.length) {
    obj = obj[arr.shift()];
  }
  return obj;
}

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath();  // returns e.g. "a.b.c"
var result = getDescendantProp(obj, propPath);

同样的方法也可实现设置子代的属性值:

代码语言:javascript
复制
function setDescendantProp(obj, desc, value) {
  var arr = desc.split('.');
  while (arr.length > 1) {
    obj = obj[arr.shift()];
  }
  obj[arr[0]] = value;
}

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath();  // returns e.g. "a.b.c"
var result = setDescendantProp(obj, propPath, 1);  // test.a.b.c will now be 1

使用函数而非代码段

JavaScript拥有first-class functions,这意味着你可以将函数直接作为参数传递给其他接口,并将他们保存在变量中或者对象的属性中等等,很多DOM的API都用这种思路进行设计,你也可以(或者应该)这样子设计你的代码:

代码语言:javascript
复制
// instead of setTimeout(" ... ", 1000) use:
setTimeout(function() { ... }, 1000); 

// instead of elt.setAttribute("onclick", "...") use:
elt.addEventListener('click', function() { ... } , false); 

Closures 也可以作为一种创建参数化函数而不连接字符串的方法.

解析 JSON(将字符串转化为JavaScript对象)

如果你在调用eval()传入的字符串参数中更包含数据(如:一个数组“[1,2,3]”)而不是代码,你应该考虑将其转换为JSON对象,这允许你用JavaScript语法的子集来表示数据。在扩展中下载JSON和JavaScript

提示:因为JSON语法子集相对于JavaScript语法子集比较有局限性,很多在JavaScript中可用的特性在JSON中就不起作用了,如:后缀都好JSON就不支持,并且,对象中的属性名在JSON中必须用引号括起来,所以在使用JSON序列化将字符串转化为JSON对象时需确认字符串格式

尽量传递数据而非代码

例如,设计用于擦除网页内容的扩展可能会在XPath中定义规则,而不是JavaScript代码。

执行这段代码应加以权限限制

如果你必须执行这段代码, 应考虑以更低的权限运行. 这建议主要应用于Components.utils.evalInSandbox 可扩展的标记语言

例子

举例: 使用eval

在下面的代码中,两种声明都返回了42。第一种是对字符串 "x + y + 1"求值;第二种是对字符串 "42"求值。

代码语言:javascript
复制
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。

代码语言:javascript
复制
var x = 5;
var str = "if (x == 5) {console.log('z is 42'); z = 42;} else z = 0;";

console.log('z is ', eval(str));

最后的表达式被计算

eval 将会返回对最后一个表达式的求值结果。

代码语言:javascript
复制
var str = 'if ( a ) { 1 + 1; } else { 1 + 2; }';
var a = true;
var b = eval(str);  // returns 2
 
console.log('b is : ' + b);

a = false;
b = eval(str);  // returns 3

console.log('b is : ' + b);

eval 作为字符串定义函数需要“(”和“)”作为前缀和后缀

代码语言:javascript
复制
var fctStr1 = 'function a() {}'
var fctStr2 = '(function a() {})'
var fct1 = eval(fctStr1)  // return undefined
var fct2 = eval(fctStr2)  // return a function

规范

Specification

Status

Comment

ECMAScript 1st Edition (ECMA-262)

Standard

Initial definition.

ECMAScript 5.1 (ECMA-262)The definition of 'eval' in that specification.

Standard

ECMAScript 2015 (6th Edition, ECMA-262)The definition of 'eval' in that specification.

Standard

ECMAScript Latest Draft (ECMA-262)The definition of 'eval' in that specification.

Living Standard

浏览器兼容性

Feature

Chrome

Edge

Firefox (Gecko)

Internet Explorer

Opera

Safari

Basic support

(Yes)

(Yes)

(Yes)

(Yes)

(Yes)

(Yes)

Feature

Android

Chrome for Android

Edge

Firefox Mobile (Gecko)

IE Mobile

Opera Mobile

Safari Mobile

Basic support

(Yes)

(Yes)

(Yes)

(Yes)

(Yes)

(Yes)

(Yes)

扫码关注腾讯云开发者

领取腾讯云代金券