このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

View in English Always switch to English

eval()

Baseline
広く利用可能

この機能は広く実装されており、多くのバージョンの端末やブラウザーで動作します。2015年7月以降、すべてのブラウザーで利用可能です。

警告: 文字列から JavaScript を実行することは、非常に大きなセキュリティリスクを伴います。eval() を使用すると、悪意のある者が任意のコードを実行することがあまりにも簡単になります。下記の eval() を使わないでください!を参照してください。

eval() 関数は、文字列として表現された JavaScript コードを評価します。ソースはスクリプトとして解釈されます。

試してみましょう

console.log(eval("2 + 2"));
// 予想される結果: 4

console.log(eval(new String("2 + 2")));
// 予想される結果: 2 + 2

console.log(eval("2 + 2") === eval("4"));
// 予想される結果: true

console.log(eval("2 + 2") === eval(new String("2 + 2")));
// 予想される結果: false

構文

js
eval(script)

引数

script

JavaScript の式、文、または一連の文を表す文字列です。式には、既存オブジェクトの変数およびプロパティを含められます。これはスクリプトとして解釈されますので、 import 宣言(モジュールの中に存在しうる)は許可されていません。

返値

与えられたコードの評価結果の値を返します。評価結果が空の場合は、undefined を返します。もし script が文字列プリミティブでなければ、 eval() は引数を変更せずに返します。

例外

コードを評価している間に発生するあらゆる例外が発生します。もし script がスクリプトとして解釈できなかった場合は SyntaxError になります。

解説

eval() はグローバルオブジェクトの関数プロパティです。

eval() 関数の引数は文字列です。 ソース文字列をスクリプト本体として評価します。つまり、文と式の両方が使用可能です。コードの完了値を返します。式の場合は、式が評価された値です。多くの文や宣言も同様に完了値を持ちますが、その結果は意外なものになることがあります(例えば、代入の完了値は代入された値ですが、 let の完了値は undefined です)。そのため、文の完了値には頼らないことをお勧めします。

厳格モードでは、 eval という名前の変数を宣言したり、 eval に代入したりすることは SyntaxError になります。

js
"use strict";

const eval = 1; // SyntaxError: Unexpected eval or arguments in strict mode

eval() の引数が文字列でない場合、eval() は引数を変更せずに返します。次の例では、プリミティブの代わりに String オブジェクトを渡すと、 eval() は文字列を評価するのではなく、 String オブジェクトを返します。

js
eval(new String("2 + 2")); // "2 + 2" を含む String オブジェクトを返す
eval("2 + 2"); // 4 を返す

一般的な方法でこの課題をうまく回避するには、eval() に渡す前に、自分で引数を文字列に変換することができます。

js
const expression = new String("2 + 2");
eval(String(expression)); // 4 を返します

直接または間接 eval

eval() の呼び出しには、直接 eval と間接 eval の 2 つのモードがあります。直接 eval は、その名前が示すとおり、グローバルな eval 関数を eval(...) で直接呼び出すことを指します。それ以外のすべては、エイリアス変数経由、メンバーアクセスやその他の式経由、またはオプショナルチェーン ?. 演算子を使用して呼び出すことも含めて、間接的なものです。

js
// 直接呼び出し
eval("x + y");

// eval を返すためにカンマ演算子を使用する間接呼び出し
(0, eval)("x + y");

// オプショナルチェーンによる間接呼び出し
eval?.("x + y");

// eval を格納し返すために変数を使用する間接呼び出し
const myEval = eval;
myEval("x + y");

// メンバーアクセスによる間接呼び出し
const obj = { eval };
obj.eval("x + y");

間接 eval は、コードが別個の <script> タグの中で評価されるように見ることができます。これはつまり次のような意味です。

  • 間接 eval はローカルスコープではなくグローバルスコープで動作し、評価されるコードは呼び出されるスコープ内のローカル変数にアクセスすることはありません。

    js
    function test() {
      const x = 2;
      const y = 4;
      // 直接呼び出し、ローカルスコープを使用
      console.log(eval("x + y")); // 結果は 6
      // 間接呼び出し、グローバルスコープを使用
      console.log(eval?.("x + y")); // x がグローバルスコープで定義されていないため、例外が発生
    }
    
  • 間接的な eval は周囲のコンテキストの厳格さを継承せず、ソース文字列自体に "use strict" ディレクティブがある場合にのみ 厳格モード になります。

    js
    function nonStrictContext() {
      eval?.(`with (Math) console.log(PI);`);
    }
    function strictContext() {
      "use strict";
      eval?.(`with (Math) console.log(PI);`);
    }
    function strictContextStrictEval() {
      "use strict";
      eval?.(`"use strict"; with (Math) console.log(PI);`);
    }
    nonStrictContext(); // Logs 3.141592653589793
    strictContext(); // Logs 3.141592653589793
    strictContextStrictEval(); // Uncaught SyntaxError: Strict mode code may not include a with statement
    

    一方、直接 eval は、呼び出すコンテキストの厳格さを継承します。

    js
    function nonStrictContext() {
      eval(`with (Math) console.log(PI);`);
    }
    function strictContext() {
      "use strict";
      eval(`with (Math) console.log(PI);`);
    }
    function strictContextStrictEval() {
      "use strict";
      eval(`"use strict"; with (Math) console.log(PI);`);
    }
    nonStrictContext(); // Logs 3.141592653589793
    strictContext(); // Uncaught SyntaxError: Strict mode code may not include a with statement
    strictContextStrictEval(); // Uncaught SyntaxError: Strict mode code may not include a with statement
    
  • もしソース文字列が厳格モードで解釈されていない場合、 var で宣言された変数と 関数宣言 は周囲のスコープに入ってしまいます。厳格モードのコンテキストでの直接 eval であった場合、または eval のソース文字列自体が厳格モードであった場合、 var と関数宣言は周囲のスコープに「漏れる」ことはありません。

    js
    // コンテキストもソース文字列も厳格モードではないため、 var は周囲のスコープで変数を作成します。
    eval("var a = 1;");
    console.log(a); // 1
    // コンテキストは厳格ではありませんが、 eval のソースは厳格なので、 b は評価されたスクリプトにスコープされます。
    eval("'use strict'; var b = 1;");
    console.log(b); // ReferenceError: b is not defined
    
    function strictContext() {
      "use strict";
      // コンテキストは厳格ですが、これは間接的なもので、文字列は厳格ではありません。
      eval?.("var c = 1;");
      // 厳密なコンテキストでのディレクティブ eval なので、 d はスコープされます。
      eval("var d = 1;");
    }
    strictContext();
    console.log(c); // 1
    console.log(d); // ReferenceError: d is not defined
    

    評価される文字列内の