內建的 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…)