この記事は技術レビューを必要としています。ぜひご協力ください。
この記事は編集レビューを必要としています。ぜひご協力ください。
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) // 関数が返される
仕様
ブラウザ実装状況
機能 | 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 をご覧ください。