Join MDN and developers like you at Mozilla's View Source conference, 12-14 September in Berlin, Germany. Learn more at https://viewsourceconf.org

この記事は技術レビューを必要としています。ぜひご協力ください

この記事は編集レビューを必要としています。ぜひご協力ください

eval() 関数は文字列を JavaScript コードとして評価します。

構文

eval(string)

引数

string
式、文、または一連の文を表す文字列です。式には、既存オブジェクトの変数およびプロパティを含められます。

説明

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

eval() 関数の引数は 1 個の文字列です。その文字列が 1 個の式に相当する場合、eval() は引数を式として評価します。引数が 1 個以上の JavaScript 文に相当する場合、 eval() は引数を文として評価します。算術式を評価する目的で eval() を呼び出してはいけません。JavaScript は算術式を自動的に評価します。

文字列として算術式を構成した場合、後でその式の評価に eval() を使用できます。 例えば x という変数があるとします。ある変数に "3 * x + 2" といった式の文字列値を代入し、そしてスクリプトの後方で eval() を呼び出すことで、 x が関わる式の評価を後回しにできます。

eval の引数が文字列でない場合、eval は引数を変更せずに返します。次の例では、String コンストラクタが記述されている場合、eval はその文字列を評価するのではなく String オブジェクトを返します。

eval(new String("2 + 2")); // returns a String object containing "2 + 2"
eval("2 + 2");             // returns 4

この制約は、toString を使用する一般的な方法で回避できます。

var expression = new String("2 + 2");
eval(expression.toString());

eval 関数を eval 以外の名前を参照して呼び出すことで間接的に使用した場合、ECMAScript 5 以降ではローカルスコープではなくグローバルスコープで機能します。これは例えると、関数定義によりグローバル関数が作成されるため、評価されたコードはその呼び出されたスコープ内のローカル変数にアクセスできなくなる、ということです。

function test() {
  var x = 2, y = 4;
  console.log(eval("x + y"));
  // 直接的な呼び出しによってローカルスコープでの使用となり、結果は 6 となる
  var geval = eval;
  console.log(geval("x + y"));
  // 間接的な呼び出しによってグローバルスコープでの使用となり、
  // `x` は未定義となるため ReferenceError が発生する
}

必要以上に eval を使わないで!

eval() は、呼び出し元の持つ権限でコードが実行される危険な関数です。悪意を持つ第三者から影響を受ける可能性がある文字列とともに eval() を実行すると、しまいにはウェブページや拡張機能の持つアクセス権にしたがってユーザーのマシン上で悪意あるコードが実行されてしまうかもしれません。さらに重要なこととして、eval() が呼び出された先のスコープを第三者から確認することができるため、同様の機能を持つ Function オブジェクトなら本来影響のないような方法でも攻撃を受ける可能性があります。

また、ここ最近の JavaScript では多くの制御構造が JS エンジンによって最適化されているのとは異なり、eval() は JS インタプリタを呼び出すため一般に代替手段より低速です。

一般的な使用例であれば、 eval() の安全(かつ高速)な代案があります。

メンバのプロパティにアクセスする

プロパティ名からプロパティ自体への変換を行うのに eval を使用してはいけません。コードが実行されるまで、アクセスしているオブジェクトのプロパティがわからない、という例について考えてみましょう。eval を使ってこのように書けます :

var obj = { a: 20, b: 30 };
var propname = getPropName();  // "a" か "b" が返される

eval( "var result = obj." + propname );

しかしながら、この場合 eval() は不要です。実際、この使い方はお勧めできません。こういう場合、プロパティアクセス演算子を使ったほうが、より早くて安全です。

var obj = { a: 20, b: 30 };
var propname = getPropName();  // "a" か "b" が返される
var result = obj[ propname ];  // obj[ "a" ] は obj.a と同じ意味

コードを評価する場合、代わりに関数を使う

JavaScript は関数を他の API の引数にしたり、変数に保存したりオブジェクトのプロパティにできる第一級関数の機能を備えています。多くの DOM API はこれを考慮して作られているので、次のように書けます(そして書くべきです):

// setTimeout(" ... ", 1000) を使う代わりに :
setTimeout(function() { ... }, 1000); 

// elt.setAttribute("onclick", " ... ") を使う代わりに :
elt.addEventListener("click", function() { ... } , false); 

文字列をつなげること無くパラメータから関数を作成したければ、クロージャを使う方法も便利です。

JSON の構文解析(文字列を JavaScript オブジェクトに変換)

データ文字列(例えば、配列: "[1, 2, 3]" など)の変換に eval() を使いたいなら、JSON に切り替えるべきです。Downloading JSON and JavaScript in extensions の記事を参考にしてください。

JSON の構文は JavaScript 構文に比べ制限があり、多くの有効な JavaScript リテラルが JSON としては構文解析されないことに注意してください。例えば、末尾に付けられたコンマは JSON では許可されず、またオブジェクトリテラルのプロパティ名(キー)は引用符で囲まないといけません。あとで JSON として構文解析される文字列を生成する際は、JSON シリアライザを使うようにしましょう。

コードの代わりにデータを渡す

例えば、ウェブページの内容を取得できるよう設計された拡張であれば、JavaScript コードの代わりに XPath を使って取得ルールを定義できます。

制限された権限でコードを実行する

どうしてもコードを実行したければ、制限された権限下での実行を検討しましょう。このアドバイスは、拡張機能や XUL アプリケーション上であれば Components.utils.evalInSandbox を使用すれば適用できます。

使用例

eval を使用する

次のコードでは、eval を含むどちらの文も 42 を返します。最初のコードは文字列 "x + y + 1" を評価します。2 番目のコードは文字列 "42" を評価します。

var x = 2;
var y = 39;
var z = "42";
eval("x + y + 1"); // 42 が返される
eval(z);           // 42 が返される

JavaScript 文からなる文字列の評価に eval を使用する

次の例は、文字列 str の評価に eval を使用しています。この文字列は console.log() 関数を使い、x が 5 なら z に 42 を代入し、それ以外の場合は z に 0 を代入してログに表示させる JavaScript 文で構成されています。2 番目の文が実行される時、eval によってこれらの文が実行され、そして文の集まりを評価して z に代入される値を返します。

var x = 5;
var str = "if (x == 5) {console.log('z is 42'); z = 42;} else z = 0; ";

console.log("z is ", eval(str));

評価される最後の式について

eval は最後に評価された式の値を返します。

var str = "if ( a ) { 1+1; } else { 1+2; }";
var a = true;
var b = eval(str);  // 2 が返される
 
console.log("b is : " + b);

a = false;
b = eval(str);  // 3 が返される

console.log("b is : " + b);

先頭と末尾に丸括弧が必要な関数定義を含む文字列を eval で評価した場合

var fctStr1 = "function a() {}"
var fctStr2 = "(function a() {})"
var fct1 = eval(fctStr1)  // undefined が返される
var fct2 = eval(fctStr2)  // 関数が返される

仕様

仕様 状況 コメント
ECMAScript 1st Edition (ECMA-262) Standard 初期定義。
ECMAScript 5.1 (ECMA-262)
The definition of 'eval' in that specification.
Standard  
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'eval' in that specification.
Standard  

ブラウザ実装状況

機能 Chrome Firefox (Gecko) Internet Explorer Opera Safari
基本サポート (有) (有) (有) (有) (有)
機能 Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
基本サポート (有) (有) (有) (有) (有) (有)

Gecko 特有の註記事項

  • 歴史的に、eval() はオプションとして評価が実行される際のコンテキストとなるオブジェクトを指定する第二引数がありました。この引数は非標準なもので、Gecko 1.9.1 (Firefox 3.5) 以降の SpiderMonkey からは削除されました。バグ 442333 をご覧ください。

関連項目

ドキュメントのタグと貢献者

タグ: 
 このページの貢献者: x2357, teoli, ethertank, masahal, Potappo, Hfjapancom
 最終更新者: x2357,