2019年9月25日

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

use strictがない場合、evalは独自のレキシカル環境を持たないため、外側からxfを見ることができます。

“eval”の使用について

現代のプログラミングでは、evalは非常に控えめに使われています。「evalは悪だ」とよく言われます。

理由は単純です。昔々、JavaScriptははるかに弱い言語で、多くのことがevalでしかできませんでした。しかし、その時代は10年前に過ぎ去りました。

現在、evalを使用する理由はほとんどありません。もし誰かがそれを使っているなら、最新の言語構造やJavaScriptモジュールに置き換えることができる可能性が高いです。

外側の変数にアクセスできる機能には副作用があることに注意してください。

コードのミニファイア(JSを本番環境にデプロイする前に圧縮するために使用されるツール)は、コードを小さくするためにローカル変数を短いもの(abなど)にリネームします。これは通常は安全ですが、ローカル変数がevalされたコード文字列からアクセスされる可能性がある場合、安全ではありません。そのため、ミニファイアはevalから見える可能性のあるすべての変数に対してそのリネームを行いません。それはコードの圧縮率に悪影響を与えます。

eval内で外側のローカル変数を使用することは、コードのメンテナンスをより困難にするため、悪いプログラミング習慣とみなされています。

このような問題から完全に安全になるための2つの方法があります。

evalされたコードが外側の変数を使用しない場合は、evalwindow.eval(...)として呼び出してください。

この方法で、コードはグローバルスコープで実行されます。

let x = 1;
{
  let x = 5;
  window.eval('alert(x)'); // 1 (global variable)
}

evalされたコードがローカル変数を必要とする場合は、evalnew Functionに変更し、それらを引数として渡します。

let f = new Function('a', 'alert(a)');

f(5); // 5

new Functionの構造については、「"new Function"の構文」の章で説明されています。これは文字列から関数を作成し、これもグローバルスコープで行われます。そのため、ローカル変数を見ることができません。しかし、上の例のように、それらを引数として明示的に渡す方がはるかに明確です。

まとめ

eval(code)の呼び出しは、コードの文字列を実行し、最後のステートメントの結果を返します。

  • 通常は必要ないため、現代のJavaScriptではめったに使用されません。
  • 外側のローカル変数にアクセスできます。それは悪い習慣とみなされます。
  • 代わりに、グローバルスコープでコードをevalするには、window.eval(code)を使用してください。
  • または、コードが外側のスコープからいくつかのデータを必要とする場合は、new Functionを使用し、それを引数として渡してください。

タスク

重要度: 4

算術式をプロンプトし、その結果を返す計算機を作成してください。

このタスクでは、式が正しいか確認する必要はありません。単に評価して結果を返すだけです。

デモを実行する

evalを使用して数式を計算しましょう。

let expr = prompt("Type an arithmetic expression?", '2*3+2');

alert( eval(expr) );

ただし、ユーザーは任意のテキストまたはコードを入力できます。

安全性を確保し、算術演算のみに限定するには、正規表現を使用してexprをチェックし、数字と演算子のみが含まれるようにします。

チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善点について提案がある場合は、コメントする代わりにGitHubのissueを送信するか、プルリクエストを提出してください。
  • 記事の内容が理解できない場合は、詳細を説明してください。
  • 数語のコードを挿入するには、<code>タグを使用し、複数行の場合は<pre>タグで囲み、10行以上の場合はサンドボックス(plnkrjsbincodepen…)を使用してください。