回答:
JScriptエンジンを実装していたとき、私はEVAL IS EVILシャツを印刷することを提唱しましたが、残念ながら私たちはそれに到達できませんでした。
evalに関する私の最大の問題は、明らかな悪意のあるコードインジェクション攻撃ではありませんが、それは確かに大きな懸念事項です。私の最大の問題は、人々が本当に小さな問題を解決するために本当に大きなハンマーとしてそれを使用する傾向があることです。私がJScriptチームにいたときの「評価」の実世界での使用のほとんどは、ルックアップテーブルを使用して簡単に解決できました。また、JScriptのすべてのオブジェクトは既にルックアップテーブルであるため、面倒な負担ではありませんでした。評価は再び、コンパイラを起動し、完全にあなたのコードを最適化するコンパイラの能力を破壊します。
この脈絡についてのさらなる考えについては、2003年の主題に関する私の記事を参照してください。
一般的な悪:
http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx
インジェクション攻撃の悪さ:
http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx
eval()ありません、クライアント(ブラウザ)コード上のセキュリティリスク。
ほとんどのセキュリティホールは、SQLインジェクションと同じ種類のホールです。つまり、ユーザー入力をJavaScriptコードに連結します。違いは、これをSQLで行わないようにする方法はありますが、JavaScriptでできることはあまりないことです。
単純で役に立たない例として、単純なJavaScript計算機:
textbox1.value = eval(textbox2.value);
正しい使用例の1つは、一般的な単語を引き出して1〜2文字の短い文字列に置き換えることでJavaScriptを圧縮するJavaScriptパッカーの一部です。パッカーは、生成された辞書に基づいて文字列置換コードとともにこれらすべてを出力し、結果を評価します。
EVAL-のような機能のないJSで行うことは不可能ないくつかのものがあります(eval、Function、そしておそらくより)。
apply例を挙げましょう。通常の関数呼び出しで使用する場合、簡単に使用できます。
foo.apply(null, [a, b, c])
しかし、新しい構文を介して作成しているオブジェクトに対してこれをどのように行いますか?
new Foo.apply(null, [a, b, c]) 機能せず、同様の形式も機能しません。
しかし、あなたは経由でこの制限を回避することができますevalかFunction(私が使用してFunction、この例では):
Function.prototype.New = (function () {
var fs = [];
return function () {
var f = fs[arguments.length];
if (f) {
return f.apply(this, arguments);
}
var argStrs = [];
for (var i = 0; i < arguments.length; ++i) {
argStrs.push("a[" + i + "]");
}
f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
if (arguments.length < 100) {
fs[arguments.length] = f;
}
return f.apply(this, arguments);
};
}) ();
例:
Foo.New.apply(null, [a, b, c]);
もちろん、Function.prototype.New使用する関数を手動で作成することもできますが、この冗長で不格好なだけでなく、(定義により)有限である必要があります。Functionコードを任意の数の引数に対して機能させることができます。
eval()ですか?」
非常にまれにしか使用しないことに同意しますが、の強力なユースケースを見つけましたeval。
Firefoxには、私が取り組んできたasm.jsという実験的な新機能があります。Javascript言語の限られたサブセットをネイティブコードにコンパイルできます。はい、これは非常に素晴らしいですが、制限があります。Javascriptの限られたサブセットは、Javascriptに埋め込まれたCに似た言語であると考えることができます。それは実際に人間が読み書きすることを意図したものではありません。
Javascriptのこの限られたサブセットでは、コンパイルされたランタイムに生成されたコードを、コンパイルされたコードに挿入することはできません。
ユーザーが使い慣れた表記法で数式を記述し、その場でasm.jsコードに変換できるようにするコードを作成しました。コードをサーバー側で処理したい(そうしない)場合evalを除き、結果のコードをブラウザーでリアルタイムに処理できるようにする唯一のツールです。
他の人が指摘したように、作業する際の最も重要なことevalは、それを安全に保つことです。そのためには、徹底的な引数チェックをeval実行し、実行時生成コードの維持と保護が一般にはるかに難しいため、「ed」コードをシンプルにします。
そうは言っても、私evalは2種類のことを使うことを楽しんでいます(おそらく、より良い、より邪悪ではない選択肢があるかもしれませんが)。
eval、「明示的にキャッシュするコード」の方法です、パフォーマンスを向上させるために使用することができます。オプティマイザーは常に改善されていることに注意してください。ただし、オプティマイザーが何を実行できるかについての保証はありません。コード内で物事を明示的にすることで、オプティマイザーがより賢明な決定を下せるようにすることができます。たとえば、このプリコンパイルされたオブジェクトイテレータアプローチは、evalオブジェクトプロパティのイテレーションに使用する場合、パフォーマンスが明らかに向上することを示しています。また、暗黙の制約チェックなどを、ほとんどまたはまったくコストをかけずに提供できる強力な型システムの始まりを示しています。
Javascriptのベテラン開発者の多くは、これがうさぎの穴だと指摘するでしょう。なぜなら、この方法でJavascriptを書き始めると、基本的に言語の使用方法が変わるからです。ただし、Javascriptを楽しむ人にとって必ずしも悪いことではないかもしれませんが、言語自体の使用方法を変更することでしか達成できない基本的な言語機能もありません。
文字列を評価し、文字列と同じ名前の既存の変数を返すevalのように見える状況があります。
いくつかのテーブルがあります:table1ResultsTable、table2ResultsTable、tableNResultsTable。同じ名前で設定された変数、つまりjQueryデータテーブルオブジェクトがあります。これらを使用してテーブルをセットアップし、jQueryデータテーブル関数を呼び出します。
各テーブルにはclass = "resultsTable"が割り当てられています。次に、テーブルをクリックしたときに変数を取得する必要があります。私はこれをやっています:
$('resultsTable).on('click', 'td', function(event) {
var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
[etc]
});
そのため、セルがクリックされたテーブルのIDを取得しています。これは、それに対応するdatatableオブジェクト変数と同じ名前です。誰かが改善のための提案を持っている場合、私はそれについて知りたいです。
event.target.parentElement.parentElement.parentElement恐ろしいです。さらに、評価可能なIDを意図的に使用していない限り、eval呼び出しが「参照エラー:[id]が定義されていません」エラーを生成することを期待します(壊れている、間違っている、終了すると奇妙なことが起こる可能性があります)重複IDを生成します)。
document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(どちらかが優れているとは言いませんが、evalよりも優れています)。Eric Lippertが指摘するように、「JScriptのすべてのオブジェクトはすでにルックアップテーブルです。」
evalJSPackerのようなアプリケーションが好む方法で、大量のコードを実行することについてのあなたの考えは何ですか?JSPacker + gzipは通常、それ自体のソリューションよりもファイルサイズが小さくなりますが、あなたが正しく指摘しているように、本質的に同じコードでコンパイラを2回起動し、さらに文字列置換を行うためのオーバーヘッドが発生します。