内置的 eval
函数允许执行代码字符串。
语法为
let result = eval(code);
例如
let code = 'alert("Hello")';
eval(code); // Hello
代码字符串可以很长,包含换行符、函数声明、变量等。
eval
的结果是最后一条语句的结果。
例如
let value = eval('1+1');
alert(value); // 2
let value = eval('let i = 0; ++i');
alert(value); // 1
eval 后的代码在当前词法环境中执行,因此它可以看到外部变量
let a = 1;
function f() {
let a = 2;
eval('alert(a)'); // 2
}
f();
它还可以更改外部变量
let x = 5;
eval("x = 10");
alert(x); // 10, value modified
在严格模式下,eval
有自己的词法环境。因此,在 eval 中声明的函数和变量在外部不可见
// reminder: 'use strict' is enabled in runnable examples by default
eval("let x = 5; function f() {}");
alert(typeof x); // undefined (no such variable)
// function f is also not visible
如果没有 use strict
,eval
不会有自己的词法环境,因此我们会在外部看到 x
和 f
。
使用 “eval”
在现代编程中,eval
的使用非常谨慎。人们常说 “eval 是邪恶的”。
原因很简单:很久很久以前,JavaScript 是一种非常弱的语言,许多事情只能通过 eval
来完成。但那个时代在十年前就过去了。
现在,几乎没有理由使用 eval
。如果有人在使用它,他们很有可能可以用现代语言结构或 JavaScript 模块 来替换它。
请注意,它访问外部变量的能力有副作用。
代码缩小器(在 JS 进入生产之前用于压缩它的工具)将局部变量重命名为较短的变量(如 a
、b
等),以使代码更小。这通常是安全的,但如果使用了 eval
,则不是,因为可以从 eval 的代码字符串中访问局部变量。因此,缩小器不会对所有可能从 eval
中可见的变量进行重命名。这会对代码压缩率产生负面影响。
在 eval
中使用外部局部变量也被认为是一种糟糕的编程实践,因为它使维护代码变得更加困难。
有两种方法可以完全避免此类问题。
如果 eval 的代码不使用外部变量,请将 eval
称为 window.eval(...)
这样,代码将在全局作用域中执行
let x = 1;
{
let x = 5;
window.eval('alert(x)'); // 1 (global variable)
}
如果 eval 的代码需要局部变量,请将 eval
更改为 new Function
并将其作为参数传递
let f = new Function('a', 'alert(a)');
f(5); // 5
new Function
结构在 “new Function” 语法 一章中有解释。它从一个字符串创建一个函数,也位于全局作用域中。因此,它看不到局部变量。但像上面的示例中那样,将它们显式地作为参数传递会更清晰。
总结
对 eval(code)
的调用会运行代码字符串并返回最后一条语句的结果。
- 在现代 JavaScript 中很少使用,因为通常没有必要。
- 可以访问外部局部变量。这被认为是不良做法。
- 相反,要在全局作用域中
eval
代码,请使用window.eval(code)
。 - 或者,如果你的代码需要来自外部作用域的一些数据,请使用
new Function
并将其作为参数传递。
评论
<code>
标签,对于多行代码 – 将它们包装在<pre>
标签中,对于 10 行以上的代码 – 使用沙箱(plnkr、jsbin、codepen…)