組み込みの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でしかできませんでした。しかし、その時代は10年前に過ぎ去りました。
現在、evalを使用する理由はほとんどありません。もし誰かがそれを使っているなら、最新の言語構造やJavaScriptモジュールに置き換えることができる可能性が高いです。
外側の変数にアクセスできる機能には副作用があることに注意してください。
コードのミニファイア(JSを本番環境にデプロイする前に圧縮するために使用されるツール)は、コードを小さくするためにローカル変数を短いもの(a、bなど)にリネームします。これは通常は安全ですが、ローカル変数がevalされたコード文字列からアクセスされる可能性がある場合、安全ではありません。そのため、ミニファイアはevalから見える可能性のあるすべての変数に対してそのリネームを行いません。それはコードの圧縮率に悪影響を与えます。
eval内で外側のローカル変数を使用することは、コードのメンテナンスをより困難にするため、悪いプログラミング習慣とみなされています。
このような問題から完全に安全になるための2つの方法があります。
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…)を使用してください。