質問
スコープで次のJavaScriptのスニペットを指定します。
var x = 10;
function sayx() {
alert(x);
}
sayx();
もちろん、メッセージボックスに「10」と表示されますが、複数の関数をネストして「x」の決定方法と対話することができます。これは、環境xを解決するときに環境がスコープチェーンをたどるからです。
evalで「再コンパイル」のレベルを実行して、実行時に新しいスコープを挿入することもできます。例:
var x = 10;
function sayx() {
alert(x);
}
function wrap(f) {
return eval('(function() { var x = 20;(' + f + ')(); })');
}
wrap(sayx)();
これは、関数のtoString関数が呼び出されて「元の」ソースが返されるためです。したがって、本質的にxをオーバーライドする新しいスコープを持つ関数のラップバージョンを作成します。結果はアラートになります。 「10」ではなく「20」を印刷するボックス。
ただし、表面上はこれは機能しているように見えますが、スコープチェーンが壊れています。関数「f」が別の場所で定義されているため、チェーン内の次のアイテムは同じではなくなります。継承したスコープチェーンには、呼び出し元の関数がアクセスすべきではない多くの参照を含めることができます。
では、サポートされている、実行可能なスコープ項目を挿入する方法はありますか?次のようなもの:
function withScope(f, scope) { ??? }
---
var x = 10, y = 10;
function dothemath() {
alert(x + y);
}
var haxthemath = withScope(dothemath, { x: 9000 });
haxthemath(); // 9010 not 20
答えは「いいえ」だと推測していますが、そのようなスコープインジェクションには「セキュリティ」の問題があると主張する人もいるかもしれませんが、とにかく(ひどく壊れていても)トリックを行うことができると考えるとそうではありません。
この利点は、本質的に独自の疑似変数を偽造できることです。
事前に感謝します。
編集、少し明確にするだけで、次のスコープチェーンを持つ関数を「withScope」にしたいと想像してください:
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
効果的に同じチェーン+私が提供するスコープを持っている関数を取り戻せるようにしたい..すなわち:
withScope(somefunc, { foo: 'bar' })
教えてください
Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Ext scope - { foo = 'bar' }
以前のすべての永続変数は、拡張スコープがそれらについて何も言っていないために見つかります。
解決
関数やクロージャのローカル変数をスコープで参照している場合、答えはノーだと思います。
functionName.call(scope、arg1、...)またはfunctionName.apply(scope、[arg1、...]);を使用して、 this
キーワードのスコープを変更できます。これをプロトタイプと一緒に使用して、説明と同様のチェーンを作成できます。オブジェクトのプロパティに何かが見つからない場合は、プロトタイプで検索されます。プロパティが存在しない場合は、チェーン内の次のプロトタイプが使用され、以降も同様です。
他のヒント
あなたが探していると思う答えは、組み込みの" with"です。ステートメント。
ただし、非推奨であり、ecmascript 6には存在しない可能性が高いため、使用は推奨しません
この種のことができると思う唯一の他の方法は、外部からjavascript環境を操作するホストアプリケーション自体の内部からです。または、rhinoを使用している場合、Java APIとJavascript間のリンクはrhinoでまさにシームレスなので、javascript内から実際に実行できます。スティーブ・イェッジが最初に指摘したとき、それは私の心を吹き飛ばしました。 JavaScriptをJavaScriptの外部から、ただしJavaScriptの内部から操作します!天才です!
ブラウザ環境にこだわっている場合は、おそらく、narcissusなど、javascriptで記述されたjavascriptインタープリターを使用できます。
関数にjavascriptの組み込みの toString
メソッドを使用しますか?
function withScope(f, scope) {
var toExec = "";
for (var prop in scope) {
toExec += "var " + prop + " = scope['" + prop + "'];"
}
toExec += "f = (" + f.toString() + ")";
eval(toExec);
return f;
}
var x = 10;
var f = function() {
console.log(x);
};
withScope(f, {x: 20})();
これは悪い考えのようですが...
スコープをいじりたいなら、Javascript 1.7で提供されている let
ステートメントをお楽しみください。 Firefoxの最新バージョンは let
をサポートしています。