evalの戻り値について
任意の文字列をJavaScriptとして評価/実行し結果を返すeval関数ですが、"var x = 3;"とか実行させたらどうなるのか疑問だったので、ちょっと試してみました。
- 基本ルール
- 文字列をJavaScriptとして評価/実行し、式が実行されていればその値を返します。
- 式が実行されていない場合undefinedが返されます。
- 複数の式が実行された場合、最後に実行された式の結果が返されます。
- リテラル/オペレーター
- 1とか"aaa"とか、new とか function とかです。
- リテラルやオペレーターは評価値を返す式になるので、それが返されます。(当たり前ですね。)
- ステートメント
- ifとかforとか。varも含まれます。
- ステートメントを実行し、式が実行されていればその値を返します。
- ただし、if文の条件式やfor文の初期化式などは、カウントされません。
サンプルです。
var stdout = document.getElementById("stdout"); function out ( obj ) { stdout.innerHTML += obj + " : " + typeof obj + "<br/>"; } // evalで文字列をJavaScriptの式として実行し結果を返す。 out( eval("1+1") ); // 2 : number // 複数の式が実行された場合、最後の式の値が返される。 out( eval("var i = 1+1; i*2") ); // 4 : number stdout.innerHTML += "---<br/>"; // 配列とか、関数とか。 out( eval("'aaa'") ); // aaa : string out( eval("[1,2,3,4]") ); // 1,2,3,4 : object out( eval("function() { return 1; }") ); // function () { return 1; } : function stdout.innerHTML += "---<br/>"; // 各種ステートメント / 実行された式があればそれが返される。/ 複数実行した場合最後のものが返される。 out( eval("var x = 'aaa';") ); // undefined : undefined out( eval("for (var i=0; i<0; i++){i;}") ); // undefined : undefined out( eval("for (var i=0; i<10; i++){i;}") ); // 9 : number out( eval("if (false){ 1; }") ); // undefined : undefined out( eval("if (true) { 1; }") ); // 1 : number out( eval("try { 1; } catch (error) { 2; }") ); // 1 : number out( eval("try { 1; } catch (error) { 2; } finally { 3; }") ); // 3 : number out( eval("try { throw 'x' } catch (error) { 2; }") ); // 2 : number
ちょっとはまったのは以下のパターン。一見値を返す式のように見えますが、文として評価されてしまうようです。そのため戻り値はundefinedになります。
- 名前付き関数
- functionオペレータではなく、functionステートメントと見なされているようです。
- てゆうか、functionステートメントとか今日知った・・・。
- オブジェクトリテラル
- ブロックステートメントと見なされているようです。
// これらはいけそうでいけないので注意 // 名前付き関数。function operatorでなくfunction statementと見なされているっぽい。 out( eval("function a() { return 1; }") ); // undefined : undefined // オブジェクトリテラルではなくブロックと見なされているっぽい。 // out( eval('{x:6, y:7}') ); // エラー // これはいける。でもNumberになる。 out( eval('{x:6}') ); // 6 : number