深入了解 Eval
Eval:運行一個代碼字符串
內置的eval函數允許執(zhí)行一串代碼。
語法是:
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的代碼是在當前的詞法環(huán)境中執(zhí)行的,所以它可以看到外部變量:
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有自己的詞法環(huán)境。因此,在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就沒有自己的詞法環(huán)境,所以我們會在外面看到x和f。
使用 eval
在現代編程中,eval的使用非常少。人們常說“eval是邪惡的”。
原因很簡單:很久很久以前,JavaScript是一門弱得多的語言,許多事情只能用eval來完成。但十年前,這段時間就過去了。
現在,幾乎沒有理由使用eval。如果有人正在使用它,他們很有可能用一個現代的語言結構或JavaScript模塊來替換它。
請注意,它訪問外部變量的能力有副作用。
將局部變量重命名為更短的變量(如a、b等),以使代碼更小。這通常是安全的,但如果使用eval,則不是,因為局部變量可以從eval的代碼字符串訪問。因此,minifier不會對eval中可能可見的所有變量進行重命名。這對代碼壓縮比有負面影響。
在eval中使用外部局部變量也被認為是一種糟糕的編程實踐,因為它使維護代碼變得更加困難。
有兩種方法可以完全避免這些問題。
如果eval的代碼不使用外部變量,請調用eval作為window.eval(…):
這樣代碼就會在全局作用域中執(zhí)行:
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
新函數的構造將在“新函數”語法一章中解釋。它從一個字符串創(chuàng)建一個函數,這個字符串也在全局范圍內。所以它看不到局部變量。但是,像上面的例子那樣,將它們顯式地作為參數傳遞要清楚得多。
