深入了解 Eval
Eval:运行一个代码字符串
内置的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
如果不使用strict, eval就没有自己的词法环境,所以我们会在外面看到x和f。
使用 eval
在现代编程中,eval的使用非常少。人们常说“eval是邪恶的”。
原因很简单:很久很久以前,JavaScript是一门弱得多的语言,许多事情只能用eval来完成。但十年前,这段时间就过去了。
现在,几乎没有理由使用eval。如果有人正在使用它,他们很有可能用一个现代的语言结构或JavaScript模块来替换它。
请注意,它访问外部变量的能力有副作用。
将局部变量重命名为更短的变量(如a、b等),以使代码更小。这通常是安全的,但如果使用eval,则不是,因为局部变量可以从eval的代码字符串访问。因此,minifier不会对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
新函数的构造将在“新函数”语法一章中解释。它从一个字符串创建一个函数,这个字符串也在全局范围内。所以它看不到局部变量。但是,像上面的例子那样,将它们显式地作为参数传递要清楚得多。